Как получить значение Enum из индекса в Java?

96

У меня есть перечисление на Java:

public enum Months
{
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}

Я хочу получить доступ к значениям перечисления по индексу, например

Months(1) = JAN;
Months(2) = FEB;
...

Как мне это сделать?

jk_
источник
12
В информатике индексы начинаются с 0, а не с 1 ;-)
fredoverflow
1
Вы уверены, что хотите этого? Как правило, вы не должны касаться порядкового номера, кроме реализации низкоуровневых структур данных (а затем используйте альтернативные механизмы, такие как имя, для сохранения).
Tom Hawtin - tackline
Вы также могли использовать константы в классе java.util.Calendar. Они пронумерованы от 0 до 11 для января - декабря. Будьте осторожны с 12, так как это UnDe December (что-то связанное с лунным календарем). Но мне просто любопытно, зачем заново изобретать колесо констант месяца, которое уже «в наличии» в JRE?
Крис Олдрич
2FredOverflow: Хорошо, я использовал неправильную индексацию. 2Том Хотин: Да, я уверен. Я сохраняю данные с помощью некоторой структуры и получаю целочисленный индекс, а не перечисление. 2Крис Олдрич: Это фиктивный пример, который не соответствует реальному случаю.
jk_
Кстати, Java 8 и более поздние версии имеют Monthвстроенный enum.
Basil

Ответы:

229

Попробуй это

Months.values()[index]
Гарри Джой
источник
37
Обратите внимание, что каждый раз будет клонироваться копия массива значений, поэтому, если вы вызываете это во внутреннем цикле кода, чувствительного к производительности, вы можете сделать статическую копию и использовать ее.
Кристофер Барбер
1
Я запутался, тогда почему бы мне не использовать вместо этого массив?
Anudeep Samaiya
@AnudeepSamaiya может быть, мы хотим везде использовать в коде правильные константы перечисления (Months.JAN) вместо месяцев [1].
Гарри Джой
@Christopher Barber вот однострочник для «создания статической копии»:, public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};тогда вы можете получить доступ к элементам с помощьюMonths i = ALL.get(index)
muelleth
Было бы проще просто использовать Months.values ​​(). Clone () или, если вы параноидально относитесь к изменчивости, заключить его в неизменяемый список (см. Коллекции)
Кристофер Барбер
20

Вот три способа сделать это.

public enum Months {
    JAN(1), FEB(2), MAR(3), APR(4), MAY(5), JUN(6), JUL(7), AUG(8), SEP(9), OCT(10), NOV(11), DEC(12);


    int monthOrdinal = 0;

    Months(int ord) {
        this.monthOrdinal = ord;
    }

    public static Months byOrdinal2ndWay(int ord) {
        return Months.values()[ord-1]; // less safe
    }

    public static Months byOrdinal(int ord) {
        for (Months m : Months.values()) {
            if (m.monthOrdinal == ord) {
                return m;
            }
        }
        return null;
    }
    public static Months[] MONTHS_INDEXED = new Months[] { null, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

}




import static junit.framework.Assert.assertEquals;

import org.junit.Test;

public class MonthsTest {

@Test
public void test_indexed_access() {
    assertEquals(Months.MONTHS_INDEXED[1], Months.JAN);
    assertEquals(Months.MONTHS_INDEXED[2], Months.FEB);

    assertEquals(Months.byOrdinal(1), Months.JAN);
    assertEquals(Months.byOrdinal(2), Months.FEB);


    assertEquals(Months.byOrdinal2ndWay(1), Months.JAN);
    assertEquals(Months.byOrdinal2ndWay(2), Months.FEB);
}

}
Тревер Шик
источник
5
public staticизменяемый (как массив, так и не- final). Эйв. И это IllegalArgumentExceptionимело бы гораздо больший смысл, чем возвращение nullбомбы.
Tom Hawtin - tackline
2

Я просто попробовал то же самое и пришел к следующему решению:

public enum Countries {
    TEXAS,
    FLORIDA,
    OKLAHOMA,
    KENTUCKY;

    private static Countries[] list = Countries.values();

    public static Countries getCountry(int i) {
        return list[i];
    }

    public static int listGetLastIndex() {
        return list.length - 1;
    }
}

У класса есть собственные значения, сохраненные внутри массива, и я использую массив, чтобы получить перечисление в позиции индекса. Как упоминалось выше, массивы начинают отсчет с 0, если вы хотите, чтобы ваш индекс начинался с «1», просто измените эти два метода на:

public static String getCountry(int i) {
    return list[(i - 1)];
}

public static int listGetLastIndex() {
    return list.length;
}

Внутри моей Main я получаю необходимые страны-объект с помощью

public static void main(String[] args) {
   int i = Countries.listGetLastIndex();
   Countries currCountry = Countries.getCountry(i);
}

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

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

Blauspecht
источник
1

Недавно у меня была такая же проблема, и я использовал решение, предоставленное Гарри Джоем. Это решение работает только с перечислением с нуля. Я бы также не стал считать это спасением, поскольку он не работает с индексами, выходящими за пределы допустимого диапазона.

Решение, которое я использовал, может быть не таким простым, но оно полностью сохраняет и не повредит производительности вашего кода даже с большими перечислениями:

public enum Example {

    UNKNOWN(0, "unknown"), ENUM1(1, "enum1"), ENUM2(2, "enum2"), ENUM3(3, "enum3");

    private static HashMap<Integer, Example> enumById = new HashMap<>();
    static {
        Arrays.stream(values()).forEach(e -> enumById.put(e.getId(), e));
    }

    public static Example getById(int id) {
        return enumById.getOrDefault(id, UNKNOWN);
    }

    private int id;
    private String description;

    private Example(int id, String description) {
        this.id = id;
        this.description= description;
    }

    public String getDescription() {
        return description;
    }

    public int getId() {
        return id;
    }
}

Если вы уверены, что никогда не выйдете за пределы диапазона своего индекса, и не хотите использовать, UNKNOWNкак я сделал выше, вы, конечно, также можете сделать:

public static Example getById(int id) {
        return enumById.get(id);
}
Мирко Брандт
источник