Преобразование целочисленного значения в соответствие с Java Enum

У меня есть перечисление вроде этого:

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

Теперь я получаю int от внешнего ввода и хочу, чтобы совпадающий вход - выбрасывание исключения, если значение не существует, нормально, но желательно, чтобы он был DLT_UNKNOWN в этом случае.

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

Ответы

Ответ 1

Вам нужно будет сделать это вручную, добавив в класс статическую карту, которая отображает целые числа в перечисления, например

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

Ответ 2

Существует статический метод values(), который документирован, но не там, где вы ожидаете его: 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];}
}

В принципе, вы можете использовать только values()[i], но есть слухи, что values() будет создавать копию массива каждый раз при его вызове.

Ответ 3

Вам нужно будет создать новый статический метод, в котором вы выполните итерацию PcapLinkType.values ​​() и сравните:

public static PcapLinkType forCode(int code) {
    for (PcapLinkType typе : PcapLinkType.values()) {
        if (type.getValue() == code) {
            return type
        }
    }
    return null;
 }

Это было бы хорошо, если бы он назывался редко. Если он вызывается часто, посмотрите на оптимизацию Map, предложенную другими.

Ответ 4

если у вас есть перечисление, подобное этому

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

то вы можете использовать его как

PcapLinkType type = PcapLinkType.values()[1]; /*convert val to a PcapLinkType */

Ответ 5

Вы можете сделать что-то подобное, чтобы автоматически зарегистрировать их все в коллекции, с помощью которой затем можно легко преобразовать целые числа в соответствующее перечисление. (BTW, добавление их к карте в конструкторе enum не разрешено. Приятно изучать новые вещи даже после многих лет использования 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);
    }
}

Ответ 6

Как говорит @MeBigFatGuy, за исключением того, что вы можете сделать блок static {...} использующим цикл над коллекцией values():

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

Ответ 7

Я знаю, что этот вопрос несколько лет, но, поскольку Java 8, тем временем, принес нам Optional, я подумал Я бы предложил решение, используя его (и Stream и 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 похож на null: он представляет случай, когда нет (действительного) значения. Но это более безопасная альтернатива null или значение по умолчанию, например DLT_UNKNOWN, потому что вы можете забыть проверить случаи null или DLT_UNKNOWN. Они являются действительными значениями PcapLinkType! Напротив, вы не можете присвоить значение Optional<PcapLinkType> переменной типа PcapLinkType. Optional заставляет вас сначала проверить действительное значение.

Конечно, если вы хотите сохранить DLT_UNKNOWN для обратной совместимости или по какой-либо другой причине, вы все равно можете использовать Optional даже в этом случае, используя orElse(), чтобы указать его как значение по умолчанию:

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

Ответ 8

Это то, что я использую:

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

Ответ 9

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

Ответ 10

Вы можете добавить статический метод в свой список, который принимает int в качестве параметра и возвращает PcapLinkType.

public static PcapLinkType of(int linkType) {

    switch (linkType) {
        case -1: return DLT_UNKNOWN
        case 0: return DLT_NULL;

        //ETC....

        default: return null;

    }
}