Comment obtenir une valeur Enum à partir d'un index en Java?

96

J'ai une énumération en Java:

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

Je veux accéder aux valeurs d'énumération par index, par exemple

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

Comment dois-je faire ça?

jk_
la source
12
En informatique, les indices commencent à 0 et non à 1 ;-)
fredoverflow
1
Êtes-vous sûr de vouloir? En règle générale, vous ne devriez pas toucher l'ordinal, autre que l'implémentation de structures de données de bas niveau (puis utiliser des mécanismes alternatifs, tels que le nom, pour la persistance).
Tom Hawtin - tackline
Vous pourriez également avoir utilisé les constantes de la classe java.util.Calendar. Ils sont numérotés de 0 à 11 pour janvier à décembre. Faites attention à 12 car c'est décembre (quelque chose à voir avec le calendrier lunaire). Mais je suis juste curieux de savoir pourquoi réinventer la roue des constantes du mois qui vient déjà «stock» dans le JRE?
Chris Aldrich le
2FredOverflow: D'accord, j'ai utilisé une mauvaise indexation. 2Tom Hawtin: Oui, j'en suis sûr. Je persiste les données avec un cadre et je récupère un index entier, pas l'énumération. 2Chris Aldrich: Ceci est juste un exemple factice qui ne correspond pas au cas réel.
jk_
À propos, Java 8 et les Monthversions ultérieures sont livrées avec une énumération intégrée.
Basil Bourque

Réponses:

229

Essaye ça

Months.values()[index]
Harry Joy
la source
37
Notez que cela clonera une copie du tableau de valeurs à chaque fois, donc si vous appelez ceci dans la boucle interne du code sensible aux performances, vous voudrez peut-être faire une copie statique et l'utiliser.
Christopher Barber
1
Je suis confus, alors pourquoi ne voudrais-je pas utiliser un tableau à la place?
Anudeep Samaiya
@AnudeepSamaiya peut être que nous voulons utiliser les constantes d'énumération appropriées (Months.JAN) dans le code au lieu de mois [1] partout.
Harry Joy du
@Christopher Barber voici un one-liner pour "faire une copie statique" public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};Months i = ALL.get(index)
:,
Il serait plus facile d'utiliser simplement Months.values ​​(). Clone () ou si vous êtes paranoïaque à propos de la mutabilité de l'envelopper dans une liste immuable (voir Collections)
Christopher Barber
20

Voici trois façons de procéder.

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
la source
5
public staticmutable (à la fois tableau et non final). Euw. Et cela IllegalArgumentExceptionaurait beaucoup plus de sens que de renvoyer une nullbombe.
Tom Hawtin - tackline
2

J'ai juste essayé la même chose et j'ai trouvé la solution suivante:

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 a ses propres valeurs enregistrées dans un tableau, et j'utilise le tableau pour obtenir l'énumération à l'indexposition. Comme mentionné ci-dessus, les tableaux commencent à compter à partir de 0, si vous voulez que votre index commence à '1', changez simplement ces deux méthodes pour:

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

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

À l'intérieur de ma main, j'obtiens l'objet de pays nécessaire avec

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

qui définit currCountry sur le dernier pays, dans ce cas, Countries.KENTUCKY.

N'oubliez pas que ce code est très affecté par ArrayOutOfBoundsExceptions si vous utilisez des indices codés en dur pour obtenir vos objets.

Blauspecht
la source
1

J'ai récemment eu le même problème et j'ai utilisé la solution fournie par Harry Joy. Cette solution ne fonctionne qu'avec une énumération à base zéro. Je ne le considérerais pas non plus comme une sauvegarde car il ne traite pas les index qui sont hors de portée.

La solution que j'ai fini par utiliser n'est peut-être pas aussi simple, mais elle est complètement sauvegardée et ne nuira pas aux performances de votre code même avec de grandes énumérations:

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

Si vous êtes sûr que vous ne serez jamais hors de portée de votre index et que vous ne voulez pas utiliser UNKNOWNcomme je l'ai fait ci-dessus, vous pouvez bien sûr également faire:

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