Преобразовать целочисленное значение в соответствующий Java Enum - PullRequest
78 голосов
/ 14 марта 2011

У меня есть следующее перечисление:

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

Ответы [ 11 ]

97 голосов
/ 14 марта 2011

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

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;
}
30 голосов
/ 12 февраля 2013

Есть статический метод 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() будет создавать копию массива каждый раз, когда он вызывается.

14 голосов
/ 14 марта 2011

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

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

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

9 голосов
/ 25 декабря 2013

если у вас есть перечисление как это

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 */
9 голосов
/ 14 марта 2011

Вы можете сделать что-то вроде этого, чтобы автоматически зарегистрировать их все в коллекцию, чтобы затем легко конвертировать целые числа в соответствующее перечисление. (Кстати, добавление их на карту в конструкторе 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);
    }
}
4 голосов
/ 17 мая 2016

Я знаю, что этому вопросу уже несколько лет, но поскольку 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);
  }
}
4 голосов
/ 14 марта 2011

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

static {
    for (PcapLinkType type : PcapLinkType.values()) {
        intToTypeMap.put(type.getValue(), type);
    }
}
3 голосов
/ 10 апреля 2012

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

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); }
                    }
3 голосов
/ 14 марта 2011

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

public static PcapLinkType of(int linkType) {

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

        //ETC....

        default: return null;

    }
}
1 голос
/ 14 марта 2011
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;    
    }    
}    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...