Pregunta Convierta un valor entero para coincidir con Java Enum


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 coincidente - lanzar una excepción si un valor no existe está bien, pero preferiblemente lo tendría DLT_UNKNOWN  en ese caso.

int val = in.readInt();
PcapLinkType type = ???; /*convert val to a PcapLinkType */

75
2018-03-13 22:08


origen


Respuestas:


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

94
2018-03-13 22:13



Hay un método estático values() cual es 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, puedes usar solo values()[i], pero hay rumores de que values() creará una copia de la matriz cada vez que se invoca.


30
2018-02-12 09:14



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, mira el Map optimización sugerida por otros.


14
2018-03-13 22:12



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 */

9
2017-12-25 07:06



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, agregándolos al mapa en el constructor enum No se permite. Es agradable 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);
    }
}

8
2018-03-13 22:19



Como dice @MeBigFatGuy, excepto que puedes hacer static {...} bloquear el uso de un bucle sobre el values() colección:

static {
    for (PcapLinkType type : PcapLinkType.values()) {
        intToTypeMap.put(type.getValue(), type);
    }
}

4
2018-03-13 22:16



Sé que esta pregunta tiene algunos años, pero como Java 8, mientras tanto, nos ha traído Optional, Pensé que ofrecería una solución usándolo (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 para el tipo de null o un valor predeterminado como DLT_UNKNOWN porque podrías olvidarte de verificar el null o DLT_UNKNOWN casos. Ambos son válidos PcapLinkType ¡valores! Por el contrario, no puede asignar un Optional<PcapLinkType> valor a una variable de tipo PcapLinkType. Optional te hace verificar primero un valor válido.

Por supuesto, si quieres retener DLT_UNKNOWN para compatibilidad con versiones anteriores o cualquier otra razón, todavía 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);
  }
}

4
2018-05-16 23:51