¿Cómo obtener el valor de enumeración del índice en Java?

96

Tengo una enumeración en Java:

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

Quiero acceder a los valores de enumeración por índice, por ejemplo

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

¿Cómo voy a hacer eso?

jk_
fuente
12
En informática, los índices comienzan en 0, no en 1 ;-)
fredoverflow
1
¿Estás seguro que quieres? En general, no debería tocar el ordinal, aparte de implementar estructuras de datos de bajo nivel (y luego, usar mecanismos alternativos, como el nombre, para la persistencia).
Tom Hawtin - tackline
También podría haber usado las constantes en la clase java.util.Calendar. Están numerados del 0 al 11 de enero a diciembre. Tenga cuidado con el 12, ya que es un mes de diciembre (algo que tiene que ver con el calendario lunar). Pero solo tengo curiosidad ¿por qué reinventar la rueda de las constantes mensuales que ya viene "stock" en el JRE?
Chris Aldrich
2FredOverflow: De acuerdo, utilicé una indexación incorrecta. 2Tom Hawtin: Sí, estoy seguro. Conservo los datos con algún marco y obtengo el índice entero, no la enumeración. 2Chris Aldrich: Este es solo un ejemplo ficticio que no coincide con el caso real.
jk_
Por cierto, Java 8 y Monthversiones posteriores vienen con una enumeración incorporada.
Basil Bourque

Respuestas:

229

Prueba esto

Months.values()[index]
Harry Joy
fuente
37
Tenga en cuenta que clonará una copia de la matriz de valores cada vez, por lo que si está llamando a esto en el ciclo interno del código sensible al rendimiento, es posible que desee hacer una copia estática y usarla.
Christopher Barber
1
Estoy confundido, entonces ¿por qué no querría usar una matriz en su lugar?
Anudeep Samaiya
@AnudeepSamaiya puede ser que queramos usar constantes de enumeración adecuadas (Months.JAN) en el código en lugar de meses [1] en todas partes.
Harry Joy
@Christopher Barber aquí hay una línea para "hacer una copia estática":, public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};luego puede acceder a los elementos conMonths i = ALL.get(index)
muelleth
Sería más fácil simplemente usar Months.values ​​(). Clone () o, si está paranoico acerca de la mutabilidad, envolverlo en una lista inmutable (ver Colecciones)
Christopher Barber
20

Aquí tienes tres formas de hacerlo.

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
fuente
5
public staticmutable (tanto de matriz como no final). Euw. Y IllegalArgumentExceptiontendría mucho más sentido que devolver una nullbomba.
Tom Hawtin - tackline
2

Intenté lo mismo y se me ocurrió la siguiente solución:

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 clase tiene sus propios valores guardados dentro de una matriz, y yo uso la matriz para obtener la enumeración en la posición de índice. Como se mencionó anteriormente, las matrices comienzan a contar desde 0, si desea que su índice comience desde '1', simplemente cambie estos dos métodos a:

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

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

Dentro de mi Main obtengo el objeto de países necesario con

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

que establece currCountry en el último país, en este caso Countries.KENTUCKY.

Solo recuerde que este código se ve muy afectado por ArrayOutOfBoundsExceptions si está utilizando índices codificados para obtener sus objetos.

Blauspecht
fuente
1

Recientemente tuve el mismo problema y utilicé la solución proporcionada por Harry Joy. Sin embargo, esa solución solo funciona con enumación de base cero. Tampoco lo consideraría un ahorro, ya que no trata con índices que están fuera de rango.

La solución que terminé usando puede que no sea tan simple, pero es completamente segura y no dañará el rendimiento de su código incluso con grandes enumeraciones:

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 está seguro de que nunca estará fuera de rango con su índice y no quiere usarlo UNKNOWNcomo lo hice anteriormente, por supuesto, también puede hacerlo:

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