Come ottenere il valore Enum dall'indice in Java?


96

Ho un enum in Java:

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

Voglio accedere ai valori enum per indice, ad es

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

Come posso farlo?


12
In informatica, gli indici iniziano da 0, non da 1 ;-)
fredoverflow

1
Sei sicuro di volere? In genere non dovresti toccare l'ordinale, a parte l'implementazione di strutture di dati di basso livello (e quindi, utilizzare meccanismi alternativi, come il nome, per la persistenza).
Tom Hawtin - tackline

Potresti anche aver usato le costanti nella classe java.util.Calendar. Sono numerati da 0 a 11 da gennaio a dicembre. Fai attenzione al 12 perché è UnDecember (qualcosa a che fare con il calendario lunare). Ma sono solo curioso di sapere perché reinventare la ruota delle costanti del mese che è già "stock" nel JRE?
Chris Aldrich

2FredOverflow: Aggree, ho usato un'indicizzazione sbagliata. 2Tom Hawtin: Sì, ne sono sicuro. Persisto i dati con alcuni framework e ottengo indietro l'indice intero, non l'enum. 2Chris Aldrich: Questo è solo un esempio fittizio che non corrisponde al caso reale.
jk_

A proposito, Java 8 e Monthversioni successive vengono fornite con un enum integrato.
Basil Bourque

Risposte:


229

Prova questo

Months.values()[index]

37
Nota che clonerà una copia dell'array dei valori ogni volta, quindi se lo chiami nel ciclo interno del codice sensibile alle prestazioni potresti voler creare una copia statica e usarla.
Christopher Barber

1
Sono confuso, allora perché non dovrei usare un array invece?
Anudeep Samaiya,

@AnudeepSamaiya potrebbe essere che vogliamo usare le costanti enum appropriate (Months.JAN) nel codice invece dei mesi [1] ovunque.
Harry Joy,

@Christopher Barber ecco una battuta per "creare una copia statica" public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};Months i = ALL.get(index)
:,

Sarebbe più facile usare semplicemente Months.values ​​(). Clone () o, se sei paranoico riguardo alla mutabilità, includerlo in un elenco immutabile (vedi Collezioni)
Christopher Barber

20

Ecco tre modi per farlo.

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 staticmutabile (sia array che non final). Euw. E IllegalArgumentExceptionavrebbe molto più senso che restituire una nullbomba.
Tom Hawtin - tackline

2

Ho appena provato lo stesso e ho trovato la seguente soluzione:

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

La classe ha i propri valori salvati all'interno di un array e io uso l'array per ottenere l'enumerazione in indexposition. Come accennato in precedenza, gli array iniziano a contare da 0, se vuoi che il tuo indice inizi da '1' cambia semplicemente questi due metodi in:

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

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

All'interno del mio Main ottengo i paesi-oggetto necessari con

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

che imposta currCountry sull'ultimo paese, in questo caso Countries.KENTUCKY.

Ricorda solo che questo codice è molto influenzato da ArrayOutOfBoundsExceptions se stai usando indizi hardcoded per ottenere i tuoi oggetti.


1

Recentemente ho avuto lo stesso problema e ho utilizzato la soluzione fornita da Harry Joy. Quella soluzione funziona solo con enumarazione a base zero. Inoltre non lo considererei salvo in quanto non si occupa di indici che sono fuori intervallo.

La soluzione che ho finito per usare potrebbe non essere così semplice ma è completamente salva e non danneggerà le prestazioni del tuo codice anche con grandi enumerazioni:

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

Se sei sicuro che non sarai mai fuori portata con il tuo indice e non vuoi usare UNKNOWNcome ho fatto sopra puoi ovviamente anche fare:

public static Example getById(int id) {
        return enumById.get(id);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.