Получить enum по его внутреннему полю - PullRequest
32 голосов
/ 06 мая 2010

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

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

Написал это:

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;
    }
}

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

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

Ответы [ 4 ]

56 голосов
/ 06 мая 2010

Вы можете использовать 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).

17 голосов
/ 06 мая 2010

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

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

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

Это один из случаев «Если он не сломан, не чините его».

0 голосов
/ 06 мая 2010

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

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

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

до перечисления.

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

0 голосов
/ 06 мая 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...