values - java enum valueof
Convertir de enum ordinal a enum tipo (9)
Tengo el tipo de enumeración ReportTypeEnum
que se pasa entre métodos en todas mis clases, pero luego necesito pasar esto en la URL, así que uso el método ordinal para obtener el valor int. Después de recibirlo en mi otra página JSP, necesito volver a convertirlo en un ReportTypeEnum
para poder continuar pasándolo.
¿Cómo puedo convertir ordinal al ReportTypeEnum
?
Utilizando Java 6 SE.
Cada enum tiene nombre (), que le da una cadena con el nombre del miembro enum.
Dado el enum Suit{Heart, Spade, Club, Diamond}
, Suit.Heart.name()
le dará Heart
.
Cada enum tiene un método valueOf()
, que toma un tipo de enumeración y una cadena, para realizar la operación inversa:
Enum.valueOf(Suit.class, "Heart")
devuelve Suit.Heart
.
Por qué alguien usaría ordinales está más allá de mí. Puede ser nanosegundos más rápido, pero no es seguro, si los miembros de la enumeración cambian, ya que otro desarrollador puede no saber que algún código se basa en valores ordinales (especialmente en la página JSP citada en la pregunta, la sobrecarga de la red y la base de datos domina completamente la tiempo, no utilizando un entero sobre una cadena).
Esto es casi una mala idea . Ciertamente, si el ordinal es persistente de facto (por ejemplo, porque alguien ha marcado la URL), eso significa que siempre debe conservar el orden de enum
en el futuro, lo que puede no ser obvio para los mantenedores de código en la línea.
¿Por qué no codificar la enum
usando myEnumValue.name()
(y decodificar a través de ReportTypeEnum.valueOf(s)
) en su lugar?
Esto es lo que hago en Android con Proguard:
public enum SomeStatus {
UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order
private static SomeStatus[] values = null;
public static SomeStatus fromInteger(int i) {
if(SomeStatus.values == null) {
SomeStatus.values = SomeStatus.values();
}
if (i < 0) return SomeStatus.values[0];
if (i >= SomeStatus.values.length) return SomeStatus.values[0];
return SomeStatus.values[i];
}
}
es corto y no tengo que preocuparme por tener una excepción en Proguard
Esto es lo que yo uso. No pretendo que sea mucho menos "eficiente" que las soluciones más simples mencionadas anteriormente. Lo que hace es proporcionar un mensaje de excepción mucho más claro que "ArrayIndexOutOfBounds" cuando se utiliza un valor ordinal no válido en la solución anterior.
Utiliza el hecho de que EnumSet javadoc especifica que el iterador devuelve elementos en su orden natural. Hay una afirmación si eso no es correcto.
La prueba JUnit4 demuestra cómo se usa.
/**
* convert ordinal to Enum
* @param clzz may not be null
* @param ordinal
* @return e with e.ordinal( ) == ordinal
* @throws IllegalArgumentException if ordinal out of range
*/
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
EnumSet<E> set = EnumSet.allOf(clzz);
if (ordinal < set.size()) {
Iterator<E> iter = set.iterator();
for (int i = 0; i < ordinal; i++) {
iter.next();
}
E rval = iter.next();
assert(rval.ordinal() == ordinal);
return rval;
}
throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}
@Test
public void lookupTest( ) {
java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
System.out.println(tu);
}
Estoy de acuerdo con la mayoría de las personas en que usar ordinal es probablemente una mala idea. Generalmente resuelvo este problema al darle a la enumeración un constructor privado que puede tomar, por ejemplo, un valor de base de datos y luego crear una función fromDbValue
estática similar a la de la respuesta de Jan.
public ReportTypeEnum {
R1(1),
R2(2),
R3(3),
R4(4),
R5(5),
R6(6),
R7(7),
R8(8);
private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);
private static Map<Integer, ReportTypeEnum> lookup;
private Integer dbValue;
private ReportTypeEnum(Integer dbValue) {
this.dbValue = dbValue;
}
static {
try {
ReportTypeEnum[] vals = ReportTypeEnum.values();
lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);
for (ReportTypeEnum rpt: vals)
lookup.put(rpt.getDbValue(), rpt);
}
catch (Exception e) {
// Careful, if any exception is thrown out of a static block, the class
// won''t be initialized
log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
}
}
public static ReportTypeEnum fromDbValue(Integer dbValue) {
return lookup.get(dbValue);
}
public Integer getDbValue() {
return this.dbValue;
}
}
Ahora puede cambiar el orden sin cambiar la búsqueda y viceversa.
Para convertir un ordinal en su representación enumeración es posible que desee hacer esto:
ReportTypeEnum value = ReportTypeEnum.values()[ordinal];
Tenga en cuenta los límites de la matriz.
Tenga en cuenta que cada llamada a los values()
devuelve una matriz recién clonada que podría afectar el rendimiento de forma negativa. Es posible que desee almacenar en caché la matriz si se va a llamar a menudo.
Ejemplo de código sobre cómo almacenar en caché los values()
.
Esta respuesta fue editada para incluir los comentarios dados dentro de los comentarios.
Podrías usar una tabla de búsqueda estática:
public enum Suit {
spades, hearts, diamonds, clubs;
private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();
static{
int ordinal = 0;
for (Suit suit : EnumSet.allOf(Suit.class)) {
lookup.put(ordinal, suit);
ordinal+= 1;
}
}
public Suit fromOrdinal(int ordinal) {
return lookup.get(ordinal);
}
}
Si voy a usar los values()
mucho:
enum Suit {
Hearts, Diamonds, Spades, Clubs;
public static final Suit values[] = values();
}
Mientras tanto, where.java:
Suit suit = Suit.values[ordinal];
Cuidado con los límites de su matriz.
public enum Suit implements java.io.Serializable, Comparable<Suit>{
spades, hearts, diamonds, clubs;
private static final Suit [] lookup = Suit.values();
public Suit fromOrdinal(int ordinal) {
if(ordinal< 1 || ordinal> 3) return null;
return lookup[value-1];
}
}
la clase de prueba
public class MainTest {
public static void main(String[] args) {
Suit d3 = Suit.diamonds;
Suit d3Test = Suit.fromOrdinal(2);
if(d3.equals(d3Test)){
System.out.println("Susses");
}else System.out.println("Fails");
}
}
Aprecio que comparta con nosotros si tiene un código más eficiente. Mi enumeración es enorme y se llama constantemente miles de veces.