Преобразование целочисленного значения в соответствие с 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;
}
}