Wie erhalte ich Enum Value aus dem Index in Java?

96

Ich habe eine Aufzählung in Java:

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

Ich möchte über den Index auf Aufzählungswerte zugreifen, z

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

Wie soll ich das machen?

jk_
quelle
12
In der Informatik beginnen die Indizes bei 0, nicht bei 1 ;-)
Fredoverflow
1
Bist du sicher, dass du willst? Im Allgemeinen sollten Sie die Ordnungszahl nicht berühren, außer Datenstrukturen auf niedriger Ebene zu implementieren (und dann alternative Mechanismen wie den Namen für die Persistenz verwenden).
Tom Hawtin - Tackline
Sie hätten auch die Konstanten in der Klasse java.util.Calendar verwenden können. Sie sind von 0 bis 11 für Januar bis Dezember nummeriert. Achten Sie auf 12, da dies UnDecember ist (was mit dem Mondkalender zu tun hat). Aber ich bin nur neugierig, warum ich die Rad-des-Monats-Konstanten neu erfinde, die bereits in der JRE "auf Lager" sind.
Chris Aldrich
2FredOverflow: Ich stimme zu, ich habe eine falsche Indizierung verwendet. 2Tom Hawtin: Ja, ich bin sicher. Ich behalte Daten mit einem bestimmten Framework bei und erhalte einen ganzzahligen Index zurück, nicht die Aufzählung. 2Chris Aldrich: Dies ist nur ein Dummy-Beispiel, das nicht mit dem tatsächlichen Fall übereinstimmt.
jk_
Java 8 und höher verfügt übrigens über eine integrierte MonthEnumeration.
Basil Bourque

Antworten:

229

Versuche dies

Months.values()[index]
Harry Joy
quelle
37
Beachten Sie, dass jedes Mal eine Kopie des Werte-Arrays geklont wird. Wenn Sie dies also in der inneren Schleife von leistungsempfindlichem Code aufrufen, möchten Sie möglicherweise eine statische Kopie erstellen und diese verwenden.
Christopher Barber
1
Ich bin verwirrt, warum sollte ich dann nicht stattdessen ein Array verwenden wollen?
Anudeep Samaiya
@AnudeepSamaiya Möglicherweise möchten wir überall im Monat die richtigen Enum-Konstanten (Months.JAN) anstelle von Monaten [1] verwenden.
Harry Joy
@ Christopher Barber hier ist ein Einzeiler für "Erstellen einer statischen Kopie": public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};Dann können Sie auf die Elemente zugreifen mitMonths i = ALL.get(index)
muelleth
Es wäre einfacher, einfach Months.values ​​(). Clone () zu verwenden oder wenn Sie paranoid in Bezug auf Veränderlichkeit sind, es in eine unveränderliche Liste zu packen (siehe Sammlungen)
Christopher Barber
20

Hier sind drei Möglichkeiten, dies zu tun.

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

}
Trever Shick
quelle
5
public staticveränderlich (sowohl Array als auch Nicht- final). Euw. Und ein IllegalArgumentExceptionwäre viel sinnvoller als eine nullBombe zurückzugeben.
Tom Hawtin - Tackline
2

Ich habe es einfach versucht und mir folgende Lösung ausgedacht:

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

Die Klasse hat ihre eigenen Werte, die in einem Array gespeichert sind, und ich verwende das Array, um die Aufzählung bei der Indexposition zu erhalten. Wie oben erwähnt, beginnen Arrays ab 0 zu zählen. Wenn Ihr Index bei '1' beginnen soll, ändern Sie einfach diese beiden Methoden in:

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

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

In meinem Main bekomme ich das benötigte Länderobjekt mit

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

Dies setzt currCountry auf das letzte Land, in diesem Fall Countries.KENTUCKY.

Denken Sie daran, dass dieser Code von ArrayOutOfBoundsExceptions stark betroffen ist, wenn Sie fest codierte Angaben verwenden, um Ihre Objekte abzurufen.

Blauspecht
quelle
1

Ich hatte kürzlich das gleiche Problem und verwendete die von Harry Joy bereitgestellte Lösung. Diese Lösung funktioniert jedoch nur mit nullbasierter Aufzählung. Ich würde es auch nicht als sicher betrachten, da es sich nicht um Indizes handelt, die außerhalb des Bereichs liegen.

Die Lösung, die ich letztendlich verwendet habe, ist vielleicht nicht so einfach, aber sie ist vollständig sicher und beeinträchtigt die Leistung Ihres Codes auch bei großen Aufzählungen nicht:

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

Wenn Sie sicher sind, dass Sie mit Ihrem Index niemals außerhalb des Bereichs liegen und nicht UNKNOWNwie oben verwendet werden möchten, können Sie natürlich auch Folgendes tun:

public static Example getById(int id) {
        return enumById.get(id);
}
Mirko Brandt
quelle