values - numeric enum java
Convierta un valor entero para coincidir con Java Enum (10)
Tengo una enumeración como esta:
public enum PcapLinkType {
DLT_NULL(0)
DLT_EN10MB(1)
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
DLT_UNKNOWN(-1);
private final int value;
PcapLinkType(int value) {
this.value= value;
}
}
Ahora obtengo un int de entrada externa y quiero la entrada correspondiente - lanzar una excepción si un valor no existe está bien, pero preferiblemente sería DLT_UNKNOWN
en ese caso.
int val = in.readInt();
PcapLinkType type = ???; /*convert val to a PcapLinkType */
Como dice @MeBigFatGuy, excepto que puedes hacer que tu bloque static {...}
use un ciclo sobre la colección values()
:
static {
for (PcapLinkType type : PcapLinkType.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
Deberá crear un nuevo método estático donde itere PcapLinkType.values () y compare:
public static PcapLinkType forCode(int code) {
for (PcapLinkType typе : PcapLinkType.values()) {
if (type.getValue() == code) {
return type;
}
}
return null;
}
Eso estaría bien si se llama raramente. Si se llama con frecuencia, observe la optimización del Map
sugerida por otros.
Esto es lo que uso:
public enum Quality {ENOUGH,BETTER,BEST;
private static final int amount = EnumSet.allOf(Quality.class).size();
private static Quality[] val = new Quality[amount];
static{ for(Quality q:EnumSet.allOf(Quality.class)){ val[q.ordinal()]=q; } }
public static Quality fromInt(int i) { return val[i]; }
public Quality next() { return fromInt((ordinal()+1)%amount); }
}
Hay un método static values()
que está documentado, pero no donde lo esperaría: http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
enum MyEnum {
FIRST, SECOND, THIRD;
private static MyEnum[] allValues = values();
public static MyEnum fromOrdinal(int n) {return allValues[n];}
}
En principio, puede usar values()[i]
justos values()[i]
, pero hay rumores de que values()
creará una copia de la matriz cada vez que se invoca.
Puede agregar un método estático en su enumeración que acepte un int
como parámetro y devuelva un PcapLinkType
.
public static PcapLinkType of(int linkType) {
switch (linkType) {
case -1: return DLT_UNKNOWN
case 0: return DLT_NULL;
//ETC....
default: return null;
}
}
Puede hacer algo como esto para registrarlos automáticamente en una colección para luego convertir fácilmente los enteros en la enumeración correspondiente. (Por cierto, agregarlos al mapa en el constructor enum no está permitido . Es bueno aprender cosas nuevas incluso después de muchos años usando Java. :)
public enum PcapLinkType {
DLT_NULL(0),
DLT_EN10MB(1),
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
DLT_UNKNOWN(-1);
private static final Map<Integer, PcapLinkType> typesByValue = new HashMap<Integer, PcapLinkType>();
static {
for (PcapLinkType type : PcapLinkType.values()) {
typesByValue.put(type.value, type);
}
}
private final int value;
private PcapLinkType(int value) {
this.value = value;
}
public static PcapLinkType forValue(int value) {
return typesByValue.get(value);
}
}
Sé que esta pregunta tiene algunos años, pero como Java 8, mientras tanto, nos trajo Optional
, pensé que ofrecería una solución para usarlo (y Stream
y Collectors
):
public enum PcapLinkType {
DLT_NULL(0),
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
// DLT_UNKNOWN(-1); // <--- NO LONGER NEEDED
private final int value;
private PcapLinkType(int value) { this.value = value; }
private static final Map<Integer, PcapLinkType> map;
static {
map = Arrays.stream(values())
.collect(Collectors.toMap(e -> e.value, e -> e));
}
public static Optional<PcapLinkType> fromInt(int value) {
return Optional.ofNullable(map.get(value));
}
}
Optional
es como null
: representa un caso cuando no hay un valor (válido). Pero es una alternativa más segura a los valores null
o predeterminados, como DLT_UNKNOWN
ya que puede olvidarse de verificar los casos null
o DLT_UNKNOWN
. ¡Ambos son valores válidos de PcapLinkType
! Por el contrario, no puede asignar un valor Optional<PcapLinkType>
a una variable de tipo PcapLinkType
. Optional
hace verificar primero un valor válido.
Por supuesto, si desea retener DLT_UNKNOWN
por compatibilidad con versiones anteriores o por cualquier otro motivo, aún puede usar Optional
incluso en ese caso, usando orElse()
para especificarlo como el valor predeterminado:
public enum PcapLinkType {
DLT_NULL(0),
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
DLT_UNKNOWN(-1);
private final int value;
private PcapLinkType(int value) { this.value = value; }
private static final Map<Integer, PcapLinkType> map;
static {
map = Arrays.stream(values())
.collect(Collectors.toMap(e -> e.value, e -> e));
}
public static PcapLinkType fromInt(int value) {
return Optional.ofNullable(map.get(value)).orElse(DLT_UNKNOWN);
}
}
Tendría que hacer esto manualmente, agregando un mapa estático en la clase que asigna enteros a las enumeraciones, como
private static final Map<Integer, PcapLinkType> intToTypeMap = new HashMap<Integer, PcapLinkType>();
static {
for (PcapLinkType type : PcapLinkType.values()) {
intToTypeMap.put(type.value, type);
}
}
public static PcapLinkType fromInt(int i) {
PcapLinkType type = intToTypeMap.get(Integer.valueOf(i));
if (type == null)
return PcapLinkType.DLT_UNKNOWN;
return type;
}
si tienes enum como este
public enum PcapLinkType {
DLT_NULL(0)
DLT_EN10MB(1)
DLT_EN3MB(2),
DLT_AX25(3),
DLT_UNKNOWN(-1);
private final int value;
PcapLinkType(int value) {
this.value= value;
}
}
entonces puedes usarlo como
PcapLinkType type = PcapLinkType.values()[1]; /*convert val to a PcapLinkType */
static final PcapLinkType[] values = { DLT_NULL, DLT_EN10MB, DLT_EN3MB, null ...}
...
public static PcapLinkType getPcapLinkTypeForInt(int num){
try{
return values[int];
}catch(ArrayIndexOutOfBoundsException e){
return DLT_UKNOWN;
}
}