Подтвердить что ты не робот

Использовать перечисления для индексов массива в Java

При чтении Effective Java я наткнулся на предложение "использовать перечисления вместо констант int". В текущем проекте я делаю что-то похожее на следующее:

int COL_NAME = 0;
int COL_SURNAME = 1;

table[COL_NAME] = "JONES" 

Как я могу использовать перечисления вместо этого для достижения этого? Из-за интерфейса, который я вынужден использовать, я должен использовать int для моего индекса. Приведенный выше пример является лишь примером. Я фактически использую API, который принимает значения int для индекса.

4b9b3361

Ответ 1

Применение одного полезного шаблона вместе с анти-шаблоном часто не выполняется; -)

В вашем случае использование массива для данных, не похожих на массив, создает проблему, когда вы хотите заменить константы int на значения enum.

Чистое (er) решение было бы чем-то вроде EnumMap со значениями enum в качестве ключей.

В качестве альтернативы вы можете использовать table[COL_NAME.ordinal()], если это абсолютно необходимо.

Если какой-либо API заставляет вас передавать значения int, но у вас есть контроль над фактическими значениями (т.е. вы можете передавать свои собственные константы), тогда вы можете переключиться на использование значений enum в вашем коде и преобразовать в/от enum только в тех местах, где ваш код взаимодействует с API. Обратная операция enumValue.ordinal() равна EnumClass.values()[ordinal]).

Ответ 2

Похоже, вы пытаетесь использовать EnumMap. Это Карта, которая обертывает массив значений.

enum Column {
   NAME, SURNAME
}

Map<Column, String> table = new EnumMap<Column, String>(Column.class);

table.put(Column.NAME, "JONES");

String name = table.get(Column.NAME);

Это было бы намного проще, если вы использовали POJO.

classPerson {
   String name;
   String surname;
}

Person person = new Person();
person.name = "JONES";
String name = person.name;

Ответ 3

Зависит от требований. Вы можете использовать Enum.ordinal() для преобразования перечисления в int.

Обратите внимание, что невозможно передать Enum непосредственно в качестве индекса.

Edit:

Другая возможность - использовать Map<YourEnum, String> map, а затем использовать map.get(EnumValue).

Ответ 4

Поскольку вы должны использовать эту таблицу и, таким образом, не можете использовать EnumMap, я лично считаю, что лучшим решением будет придерживаться того, что у вас есть. В перечислении ординальные значения элементов не должны иметь никакого внутреннего значения, в то время как в вашем случае они действуют, поскольку они используются в качестве индексов в таблице.

Проблема заключается в том, что вы не используете перечисления, вам нужны магические значения для извлечения данных столбцов из таблицы. В этом случае использование целочисленных констант является правильным инструментом для задания, если только вы не справитесь с основной проблемой этой таблицы.

Теперь вы можете заняться этим, обернув таблицу в свой собственный класс, которая обращается к ней, и использует перечисления в этом классе и из него. Но это вводит больше кода, другого слоя косвенности и на самом деле не решает каких-либо проблем для вас, за исключением того, что перечисление немного проще в обслуживании, чем список значений int (сильно компенсируется тем, что вам нужно поддерживать обертку, которую вы сейчас написали).

Вы можете рассмотреть эту работу, если вы пишете публичный API, который будут использовать другие люди, поскольку он не будет зависеть от некоторых магических значений, которые могут со временем меняться (плотная связь, которая сломает вещи). Если вы, то, вероятно, будет использоваться оболочка, которая использует EnumMap внутри.

В противном случае оставьте его как есть.

Ответ 5

В зависимости от значений вашего массива вы можете вместо этого искать объект. Например, если ваш массив выглядит примерно так:

person[FIRST_NAME] = "Jim Bob"
person[SURNAME] = "Jones"
person[ADDRESS] = "123 ABC St"
person[CITY] = "Pleasantville"
...

Тогда то, что вы действительно хотите, это что-то вроде этого

Person jimBob = new Person("Jim Bob", "Jones");
jimBob.setAddress("123 ABC St", "Pleasantville", "SC");
....

Смотрите Рефакторинг: замените массив на объект

Ответ 6

Я также столкнулся с этой проблемой, и, исходя из мира С++, я не ожидал столкнуться с этим.

Красота перечисления - это то, что может создать ряд связанных констант с уникальными значениями, где фактическое значение не имеет значения. Их использование делает код более легким для чтения и защищает от переменных, которые установлены на недопустимые значения перечисления (особенно на Java), но в такой ситуации это большая боль. Хотя у вас может быть "enum Pets {CAT, BIRD, DOG}", и на самом деле не важно, какое значение представляют CAT, BIRD и DOG, так приятно и чисто писать:   myPets [CAT] = "Dexter";   myPets [BIRD] = "Полли";   MyPets [DOG] = "Boo-Rooh";

В моей ситуации я закончил писать функцию преобразования, в которой вы передаете значение перечисления, и я возвращаю константу. Я ненавижу делать это со страстью, но это единственный чистый способ, который я знаю, чтобы поддерживать удобство и проверку ошибок перечисления.

private int getPetsValue(Pets inPet) {

    int value = 0; 
    switch (inPet) {

        case CAT:    value = 0;    break;
        case BIRD:   value = 1;    break;
        case DOG:    value = 2;    break;
        default:
            assert(false);
            value = 0;
            break;
    }
    return value;
}

Ответ 7

Вы можете определить enum с помощью такого конструктора:

public enum ArrayIndex {
    COL_NAME(0), COL_SURNAME(1);
    private int index;

    private ArrayIndex(int index) {
    this.index = index;
    }

public int getIndex() {
    return this.index;
}
};   

И затем используйте его следующим образом:

public static void main (String args[]) {
    System.out.println("index of COL_NAME is " + ArrayIndex.COL_NAME.getIndex());
}