Program Tip

정수 값을 일치하는 Java Enum으로 변환

programtip 2020. 10. 9. 12:15
반응형

정수 값을 일치하는 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 */

Integer를 열거 형에 매핑하는 클래스에 정적 맵을 추가하여 수동으로 수행해야합니다.

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

이 정적 방법이다 되고 문서화,하지만 당신이 그것을 기대하지 여기서 http://docs.oracle.com/javase/tutorial/java/javaOO/enum.htmlvalues()

enum MyEnum {
    FIRST, SECOND, THIRD;
    private static MyEnum[] allValues = values();
    public static MyEnum fromOrdinal(int n) {return allValues[n];}
}

원칙적으로를 사용할 수 values()[i]있지만 values()호출 될 때마다 배열의 복사본을 만드는 소문 이 있습니다.


PcapLinkType.values ​​()를 반복하고 비교하는 새로운 정적 메서드를 만들어야합니다.

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

드물게 호출하면 괜찮을 것입니다. 자주 호출되는 경우 Map다른 사람들이 제안한 최적화 를 살펴보십시오 .


이와 같은 작업을 수행하여 모든 항목을 컬렉션에 자동으로 등록한 다음 정수를 해당 열거 형으로 쉽게 변환 할 수 있습니다. (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);
    }
}

이와 같은 열거 형이 있다면

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

@MeBigFatGuy가 말했듯이 static {...}블록이 values()컬렉션에 대해 루프를 사용 하도록 할 수 있다는 점을 제외하고는 다음과 같습니다.

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

나는이 질문은 몇 살 알고 있지만, 자바 8 바와 같이, 그 사이에, 우리를 데리고 Optional, 나는 (그것을 사용하여 솔루션을 제공 할 거라고 생각 StreamCollectors) :

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 is like null: it represents a case when there is no (valid) value. But it is a more type-safe alternative to null or a default value such as DLT_UNKNOWN because you could forget to check for the null or DLT_UNKNOWN cases. They are both valid PcapLinkType values! In contrast, you cannot assign an Optional<PcapLinkType> value to a variable of type PcapLinkType. Optional makes you check for a valid value first.

Of course, if you want to retain DLT_UNKNOWN for backward compatibility or whatever other reason, you can still use Optional even in that case, using orElse() to specify it as the default value:

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

You could add a static method in your enum that accepts an int as a parameter and returns a PcapLinkType.

public static PcapLinkType of(int linkType) {

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

        //ETC....

        default: return null;

    }
}

This is what I use:

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

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

There is no way to elegantly handle integer-based enumerated types. You might think of using a string-based enumeration instead of your solution. Not a preferred way all the times, but it still exists.

public enum Port {
  /**
   * The default port for the push server.
   */
  DEFAULT("443"),

  /**
   * The alternative port that can be used to bypass firewall checks
   * made to the default <i>HTTPS</i> port.
   */
  ALTERNATIVE("2197");

  private final String portString;

  Port(final String portString) {
    this.portString = portString;
  }

  /**
   * Returns the port for given {@link Port} enumeration value.
   * @return The port of the push server host.
   */
  public Integer toInteger() {
    return Integer.parseInt(portString);
  }
}

참고URL : https://stackoverflow.com/questions/5292790/convert-integer-value-to-matching-java-enum

반응형