Pertanyaan Ubah nilai integer ke Java Enum yang cocok


Saya sudah enum seperti ini:

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

Sekarang saya mendapatkan int dari input eksternal dan menginginkan masukan yang sesuai - melempar pengecualian jika nilai tidak ada ok, tetapi sebaiknya saya memilikinya DLT_UNKNOWN  dalam hal itu.

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

75
2018-03-13 22:08


asal


Jawaban:


Anda perlu melakukan ini secara manual, dengan menambahkan peta statis di kelas yang memetakan Bilangan bulat ke enum, seperti

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



Ada metode statis values() yang aku s didokumentasikan, tetapi tidak di mana Anda mengharapkannya: 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];}
}

Pada prinsipnya, Anda bisa menggunakan saja values()[i], tetapi ada desas-desus itu values() akan membuat salinan dari array setiap kali itu dipanggil.


30
2018-02-12 09:14



Anda harus membuat metode statis baru di mana Anda mengulang-ulang PcapLinkType.values ​​() dan membandingkan:

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

Itu akan baik-baik saja jika itu disebut jarang. Jika sering disebut, maka lihatlah Map optimasi yang disarankan oleh orang lain.


14
2018-03-13 22:12



jika kamu punya enum seperti ini

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

maka Anda bisa menggunakannya seperti itu

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

9
2017-12-25 07:06



Anda dapat melakukan sesuatu seperti ini untuk secara otomatis mendaftarkan semuanya ke dalam koleksi yang kemudian dapat dengan mudah mengkonversi bilangan bulat ke enum yang sesuai. (BTW, menambahkannya ke peta di enum konstruktor tidak diizinkan. Sangat menyenangkan untuk mempelajari hal-hal baru bahkan setelah bertahun-tahun menggunakan 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



Seperti yang @MeBigFatGuy katakan, kecuali Anda bisa membuatnya static {...} blok menggunakan loop di atas values() koleksi:

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

4
2018-03-13 22:16



Saya tahu pertanyaan ini sudah berumur beberapa tahun, tetapi karena Java 8, pada saat itu, telah membawa kita Optional, Saya pikir saya akan menawarkan solusi dengan menggunakannya (dan Stream dan 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 seperti null: itu mewakili kasus ketika tidak ada nilai (valid). Tapi itu adalah alternatif yang lebih aman null atau nilai default seperti DLT_UNKNOWN karena Anda bisa lupa untuk memeriksa null atau DLT_UNKNOWN kasus. Keduanya valid PcapLinkType nilai! Sebaliknya, Anda tidak dapat menetapkan Optional<PcapLinkType> nilai ke variabel tipe PcapLinkType. Optional membuat Anda memeriksa nilai yang valid terlebih dahulu.

Tentu saja, jika Anda ingin mempertahankannya DLT_UNKNOWN untuk kompatibilitas ke belakang atau alasan apa pun lainnya, Anda masih dapat menggunakannya Optional bahkan dalam kasus itu, menggunakan orElse() untuk menetapkannya sebagai nilai default:

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