Получить перечисление по его внутреннему полю

Имейте перечисление с внутренними полями, видом карты.

Теперь мне нужно получить перечисление по его внутреннему полю.

Написал это:

package test;

/**
 * Test enum to test enum =)
 */
public enum TestEnum {
    ONE(1), TWO(2), THREE(3);

    private int number;

    TestEnum(int number) {
        this.number = number;
    }      

    public TestEnum findByKey(int i) {
        TestEnum[] testEnums = TestEnum.values();
        for (TestEnum testEnum : testEnums) {
            if (testEnum.number == i) {
                return testEnum;
            }
        }
        return null;
    }
}

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

Есть ли другой способ сделать то же самое?

Ответ 1

Вы можете использовать static Map<Integer,TestEnum> с инициализатором static, который заполняет его значениями TestEnum, заданными их полями number.

Обратите внимание, что findByKey сделано static, а number также сделано final.

import java.util.*;

public enum TestEnum {
    ONE(1), TWO(2), SIXTY_NINE(69);

    private final int number;    
    TestEnum(int number) {
        this.number = number;
    }

    private static final Map<Integer,TestEnum> map;
    static {
        map = new HashMap<Integer,TestEnum>();
        for (TestEnum v : TestEnum.values()) {
            map.put(v.number, v);
        }
    }
    public static TestEnum findByKey(int i) {
        return map.get(i);
    }

    public static void main(String[] args) {
        System.out.println(TestEnum.findByKey(69)); // prints "SIXTY_NINE"

        System.out.println(
            TestEnum.values() == TestEnum.values()
        ); // prints "false"
    }
}

Теперь вы можете ожидать, что findByKey будет O(1).

Ссылки

Связанные вопросы


Примечание в values()

Второй оператор println в методе main показывает: values() возвращает вновь выделенный массив с каждой инволюцией! Исходное решение O(N) могло бы немного улучшить, вызвав только один раз values() и кешируя массив, но в среднем это решение будет O(N).

Ответ 2

Хотя кто-то предложил использовать Map<Integer, TestEnum> дважды подумать об этом.

Ваше исходное решение, особенно для небольших перечислений, может быть больше, чем при использовании HashMap.

HashMap, вероятно, будет не быстрее, пока ваше перечисление не содержит как минимум 30-40 элементов.

Это один случай "Если он не сломан, не исправляйте его".

Ответ 3

У вас должен быть HashMap с номерами в виде ключей и значениями перечисления как значения.

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

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

Ответ 4

Одним из решений является добавление

public final Test[] TESTS = { null, ONE, TWO, THREE };

public static Test getByNumber(int i) {
    return TESTS[i];
}

К перечислению.

Если внутренние данные не являются целыми числами, вы можете создать карту, которую вы заполняете в инициализаторе static { ... }. Эта карта позже может быть использована в методе getByNumber выше.