Pobieranie informacji po indeksie w tablicy zawsze jest problematyczne. Częstym przypadkiem jest, że musimy przetworzyć tablicę gdzie elementy znajdują się w stałych, z góry określonych pozycjach. Zazwyczaj kończy się to wstawieniem „magicznej liczby” jak w przykładzie poniżej.

String[] employeeInfo = line.split(DELIMITER);
String id = employeeInfo[0];
String firstName = employeeInfo[1];
String lastName = employeeInfo[2];

Jednak sprawia to, że jesteśmy zdani jedynie na prawidłowe nazwy zmiennych, które opisują daną wartość.

Można jednak nieco poprawić czytelność takiego kodu. Wystarczy przypisać te „magiczne liczby” do stałych. Dzięki takiemu zabiegowi ich nazwy będą objaśniać co się tam znajduje. Natomiast jeszcze lepszym pomysłem jest stworzenie enuma, który będzie przechowywał te informacje w specjalnie wydzielonym miejscu.

private enum EmployeeInfo {
    ID(0),
    FIRST_NAME(1),
    LAST_NAME(2);
    
    private final int index;

    EmployeeInfo(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }
}

Zamiast przechowywać numer indeksu możemy też oczywiście wykorzystać wbudowaną w enum metodę ordinal(), jednak nie polecam tego sposobu, ponieważ wiążemy kolejność elementów z indeksami co może być szczególnie kłopotliwe przy refactoringu lub w momencie, kiedy któryś z indeksów nie jest dla nas istotny i chcemy go pominąć.

Po takim zabiegu nasz parser wyglądałby tak:

String[] employeeInfo = line.split(DELIMITER);
String id = employeeInfo[EmployeeInfo.ID.getIndex()];
String firstName = employeeInfo[EmployeeInfo.FIRST_NAME.getIndex()];
String lastName = employeeInfo[EmployeeInfo.LAST_NAME.getIndex()];

Jak widać pozbyliśmy się „magicznych liczb”, ale niestety nasz kod stracił nieco na kompaktowości. Na szczęście dzięki zastosowaniu enuma, możemy trochę go usprawnić.

private enum EmployeeInfo {
    ...
    public String from(String[] array) {
        return array[getIndex()];
    }
}
String[] employeeInfo = line.split(DELIMITER);
String id = EmployeeInfo.ID.from(employeeInfo);
String firstName = EmployeeInfo.FIRST_NAME.from(employeeInfo);
String lastName = EmployeeInfo.LAST_NAME.from(employeeInfo);

Dzięki takiemu zabiegowi zachowujemy czytelność oraz możliwość łatwego refactoringu naszego kodu.

Idealnym zastosowaniem takiego podejścia jest oczywiście jedynie przygotowanie docelowej klasy, która będzie zawierać wszystkie potrzebne przez nas pola w dalszym procesowaniu. Fragment, w którym parsujemy nasz ciąg znaków będzie w ten sposób przejrzysty oraz samodokumentujący się.