Як отримати значення 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;
...

Як мені це зробити?


12
В інформатиці індекси починаються з 0, а не з 1 ;-)
fredoverflow

1
Ви впевнені, що хочете? Як правило, ви не повинні торкатися порядкового номера, крім реалізації низькорівневих структур даних (а потім використовуйте альтернативні механізми, такі як ім'я, для збереження).
Том Хоутін - таклін

Ви також могли використовувати константи в класі java.util.Calendar. Вони пронумеровані 0 - 11 для січня - грудня. Будьте обережні, оскільки це 12 грудня (щось пов’язане з місячним календарем). Але мені просто цікаво, навіщо заново винаходити колесо місячних констант, яке вже приходить на "запас" в JRE?
Chris Aldrich

2FredOverflow: Погодьтеся, я використав неправильну індексацію. Том Хотін: Так, я впевнений. Я зберігаю дані з певним фреймворком і отримую цілий індекс, а не перелік. Кріс Олдріч: Це лише фіктивний приклад, який не відповідає реальному випадку.
jk_

До речі, Java 8 і пізніше поставляється з Monthвбудованим переліченням .
Василь Бурк

Відповіді:


229

Спробуйте це

Months.values()[index]

37
Зверніть увагу, що кожен раз клонуватиме копію масиву значень, тому, якщо ви викликаєте це у внутрішній цикл коду, чутливого до продуктивності, можливо, ви захочете зробити статичну копію та використовувати це.
Крістофер Барбер,

1
Я заплутаний, чому б я тоді не хотів використовувати масив?
Anudeep Samaiya

@AnudeepSamaiya може бути, ми хочемо використовувати правильні константи перерахування (Months.JAN) у коді замість місяців [1] скрізь.
Harry Joy

@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). Euw. І це IllegalArgumentExceptionмало б набагато більше сенсу, ніж повернення nullбомби.
Tom Hawtin - таклін

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 для останньої країни, в даному випадку Countries.KENTUCKY.

Просто пам’ятайте, що на цей код дуже впливає ArrayOutOfBoundsExceptions, якщо ви використовуєте жорстко закодовані індикатори для отримання своїх об’єктів.


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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.