Bagaimana cara mendapatkan nilai enum dari nilai string di Jawa?

1984

Katakanlah saya punya enum yang adil

public enum Blah {
    A, B, C, D
}

dan saya ingin mencari nilai enum string, misalnya "A"yang mana Blah.A. Bagaimana mungkin melakukan ini?

Apakah Enum.valueOf()metode yang saya butuhkan? Jika demikian, bagaimana saya menggunakan ini?

Maleakhi
sumber

Jawaban:

2259

Ya, Blah.valueOf("A")akan memberimu Blah.A.

Perhatikan bahwa nama harus sama persis , termasuk kasus: Blah.valueOf("a")dan Blah.valueOf("A ")keduanya melempar IllegalArgumentException.

Metode statis valueOf()dan values()dibuat pada waktu kompilasi dan tidak muncul dalam kode sumber. Mereka muncul di Javadoc, meskipun; misalnya, Dialog.ModalityTypemenunjukkan kedua metode.

Michael Myers
sumber
100
Untuk referensi, Blah.valueOf("A")metode ini case-sensitive dan tidak mentolerir ruang kosong asing, sehingga solusi alternatif yang diusulkan di bawah ini oleh @ JoséMi.
Brett
3
@ Michael Myers, Karena jawaban ini adalah yang paling banyak dipilih sejauh ini, haruskah saya mengerti bahwa ini adalah praktik yang baik untuk mendefinisikan enum dan nilai String-nya menjadi persis sama?
Kevin Meredith
4
@KevinMeredith: Jika Anda maksud toString()nilainya, tidak, saya tidak akan mengatakan itu. name()akan memberi Anda nama sebenarnya yang ditentukan dari konstanta enum kecuali Anda menimpanya.
Michael Myers
3
Apa yang sebenarnya Anda maksud dengan "dibuat pada waktu kompilasi dan tidak muncul dalam kode sumber." ?
treesAreEverywhere
8
@treesAreEverywhere Lebih khusus lagi, metode-metode tersebut dihasilkan (atau disintesis ) oleh kompiler. enum Blah {...}Definisi aktual seharusnya tidak mencoba untuk menyatakan sendiri valuesatau tidak valuesOf. Ini seperti bagaimana Anda dapat menulis "AnyTypeName.class" meskipun Anda tidak pernah benar-benar mendeklarasikan variabel anggota "kelas"; kompiler membuat semuanya Hanya Bekerja. (Jawaban ini mungkin tidak lagi berguna bagi Anda 3 bulan kemudian, tetapi untuk berjaga-jaga.)
Ti Strga
864

Solusi lain jika teks tidak sama dengan nilai enumerasi:

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;

    Blah(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public static Blah fromString(String text) {
        for (Blah b : Blah.values()) {
            if (b.text.equalsIgnoreCase(text)) {
                return b;
            }
        }
        return null;
    }
}
JoséMi
sumber
396
throw new IllegalArgumentException("No constant with text " + text + " found")akan lebih baik daripada return null.
whiskeysierra
8
@whiskeysierra Jon Skeet tidak akan setuju dengan itu. stackoverflow.com/questions/1167982/…
Sanghyun Lee
11
@Sangdol Bisakah Anda memberi tahu kami mengapa mengembalikan null lebih baik?
whiskeysierra
57
@Sangdol biasanya adalah hal yang baik untuk memeriksa apa yang dilakukan SUN - oops - Oracle dalam situasi yang sama. Dan sebagai Enum.valueOf () menunjukkan ini IS praktek terbaik untuk membuang Exception dalam kasus ini. Karena ini adalah situasi yang luar biasa. "Optimalisasi kinerja" adalah alasan buruk untuk menulis kode yang tidak dapat dibaca ;-)
raudi
5
Nah, Anda juga dapat menggunakan anotasi @Nullable untuk menjadikannya "dapat dibaca" ;-)
JoséMi
121

Inilah utilitas bagus yang saya gunakan:

/**
 * A common method for all enums since they can't have another base class
 * @param <T> Enum type
 * @param c enum type. All enums must be all caps.
 * @param string case insensitive
 * @return corresponding enum, or null
 */
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string) {
    if( c != null && string != null ) {
        try {
            return Enum.valueOf(c, string.trim().toUpperCase());
        } catch(IllegalArgumentException ex) {
        }
    }
    return null;
}

Kemudian di kelas enum saya, saya biasanya memiliki ini untuk menyimpan mengetik:

public static MyEnum fromString(String name) {
    return getEnumFromString(MyEnum.class, name);
}

Jika enum Anda tidak semuanya tertutup, ubah saja Enum.valueOfgarisnya.

Sayang sekali aku tidak bisa menggunakan T.classuntuk Enum.valueOfsebagai Tdihapus.

Geoffrey Zheng
sumber
176
Blok pengunci kosong itu benar-benar membuatku gila, maaf.
whiskeysierra
32
@LazloBonin: Pengecualian adalah untuk kondisi luar biasa, bukan untuk aliran kontrol. Dapatkan sendiri salinan Java yang Efektif .
Pasang kembali Monica - M. Schröder
10
Jika Java API yang ingin Anda gunakan melempar pengecualian dan Anda tidak ingin kode Anda melempar satu, Anda bisa menelan pengecualian seperti ini, atau menulis ulang logika dari awal sehingga tidak ada pengecualian yang dilemparkan di tempat pertama. Menelan pengecualian sering kali merupakan kejahatan yang lebih kecil.
Nate CK
47
Mengerikan! Selalu, selalu tangkap pengecualian di mana Anda bisa menanganinya. Contoh di atas adalah contoh sempurna bagaimana TIDAK melakukannya . Mengapa? Jadi ia mengembalikan NULL, dan penelepon kemudian harus memeriksa NULL atau melempar NPE. Jika penelepon tahu cara menangani situasi kemudian melakukan jika vs coba-tangkap mungkin terlihat sedikit lebih elegan, TETAPI jika dia tidak bisa menangani dia harus lulus nol lagi dan penelepon penelepon lagi harus memeriksa terhadap NULL , dll.
raudi
10
Agar adil dengan solusi di atas, ada benar-benar menggunakan kasus yang mengharuskan Anda untuk mengembalikan nol daripada membuang IllegalArgumentException dan memutus aliran program Anda, misalnya, memetakan enum antara skema layanan web dan skema database di mana mereka tidak selalu satu -untuk satu. Namun, saya setuju bahwa blok penangkap tidak boleh dibiarkan kosong. Letakkan beberapa kode seperti log.warn atau sesuatu untuk tujuan pelacakan.
Adrian M
102

Gunakan pola dari Joshua Bloch, Java Efektif :

(disederhanakan untuk singkatnya)

enum MyEnum {
    ENUM_1("A"),
    ENUM_2("B");

    private String name;

    private static final Map<String,MyEnum> ENUM_MAP;

    MyEnum (String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    // Build an immutable map of String name to enum pairs.
    // Any Map impl can be used.

    static {
        Map<String,MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
        for (MyEnum instance : MyEnum.values()) {
            map.put(instance.getName(),instance);
        }
        ENUM_MAP = Collections.unmodifiableMap(map);
    }

    public static MyEnum get (String name) {
        return ENUM_MAP.get(name);
    }
}

Lihat juga:

Contoh Oracle Java menggunakan Enum dan Peta instance

Perintah eksekusi dari blok statis dalam tipe Enum

Bagaimana saya bisa mencari Java enum dari nilai String-nya

Darrell Teague
sumber
4
jika Joshua Bloch mengatakannya maka ini adalah satu-satunya cara untuk pergi :-). Sayang sekali bahwa saya selalu harus gulir ke bawah sini.
dermoritz
11
Ini bahkan lebih sederhana di Java 8 seperti yang dapat Anda lakukan: Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))Saya juga merekomendasikan untuk meng-override ke Strtr () (diteruskan melalui konstruktor) dan menggunakan itu alih-alih nama, terutama jika Enum dikaitkan dengan data serial karena ini memungkinkan Anda mengontrol casing tanpa memberikan Sonar cocok.
Novaterata
1
Java 8 tentu bisa / akan mengubah banyak jawaban (lebih baik) di forum ini. Namun tidak yakin pernah memiliki ekor (Sonar) mengibaskan anjing (kode aplikasi).
Darrell Teague
3
Jika Anda akan memasukkannya ke dalam unmodifiableMap, tetap tidak ada manfaatnya untuk memulai dengan ConcurrentHashMap. Cukup gunakan a HashMap. (Jika Anda memiliki Guava ImmutableMapmaka saya akan merekomendasikan itu sebagai gantinya!)
Daniel Pryden
9
Inisialisasi statis secara inheren disinkronkan , jadi sama sekali tidak ada alasan untuk digunakan di ConcurrentHashMapsini, di mana peta tidak pernah dimodifikasi setelah inisialisasi. Karenanya mengapa bahkan misalnya contoh dalam JLS itu sendiri menggunakan reguler HashMap.
Radiodef
74

Anda juga harus berhati-hati dengan kasus Anda. Biarkan saya jelaskan: melakukan Blah.valueOf("A")pekerjaan, tetapi Blah.valueOf("a")tidak akan berhasil. Kemudian lagi Blah.valueOf("a".toUpperCase(Locale.ENGLISH))akan berhasil.

sunting
Diubah toUpperCasemenjadi toUpperCase(Locale.ENGLISH)berdasarkan tc. komentar dan dokumen java

sunting2 Di android Anda harus menggunakan Locale.US, sebagai sulai menunjukkan .

João Portela
sumber
6
Waspadai lokasi default!
tc.
3
Untuk Anda pengguna Android di luar sana, saya ingin menunjukkan bahwa dokumentasi Android secara eksplisit mendorong penggunaan Locale.USinput / output yang dapat dibaca mesin.
sulai
2
@ Trengot Ya, sayangnya. Turki adalah contoh yang bagus. Gabungkan ini dengan penanganan rusak pada charset default Java (default ke Latin pada Windows daripada Unicode) dan Anda akan menemukan itu hampir selalu tidak aman untuk menggunakan versi metode metode default yang menerima charset atau lokal. Anda hampir selalu harus mendefinisikannya secara eksplisit.
Stijn de Witt
Tidak yakin Java "default" charsets et al "broken" per se tetapi diberikan, default ke UTF-8 sebagai pengganti override (yang harus dilakukan selalu eksplisit) akan membuat sistem yang lebih baik untuk programmer junior yang umumnya gagal memahami konsep charset.
Darrell Teague
38

Berikut adalah metode yang dapat melakukannya untuk Enum apa pun, dan tidak peka huruf besar-kecil.

/** 
 * Finds the value of the given enumeration by name, case-insensitive. 
 * Throws an IllegalArgumentException if no match is found.  
 **/
public static <T extends Enum<T>> T valueOfIgnoreCase(
        Class<T> enumeration, String name) {

    for (T enumValue : enumeration.getEnumConstants()) {
        if (enumValue.name().equalsIgnoreCase(name)) {
            return enumValue;
        }
    }

    throw new IllegalArgumentException(String.format(
        "There is no value with name '%s' in Enum %s",
        name, enumeration.getName()
    ));
}
Patrick Arnesen
sumber
Variasi ini melakukannya dengan benar: equalsIgnoreCaseadalah jalan yang harus ditempuh. +1
Stijn de Witt
Seperti halnya insensivitas tetapi ... lebih suka Enums daripada (acak) penugasan String untuk kunci dan ... minor tapi iterasi kurang berkinerja untuk pencarian yang mungkin berulang. Karenanya imp dari EnumMap et al.
Darrell Teague
Ini tidak bekerja ! Saya mengubah equalsIgnoreCase menjadi sama dengan untuk tujuan saya. Kode gagal meskipun kedua input sama sama persis.
MasterJoe2
36

Menggunakan Blah.valueOf(string)itu yang terbaik tetapi Anda juga bisa menggunakannya Enum.valueOf(Blah.class, string).

Peter Lawrey
sumber
1
Peka huruf besar-kecil, tidak membantu!
Murtaza Kanchwala
@MurtazaKanchwala Bisakah Anda mengklarifikasi komentar Anda? Apa yang sedang Anda coba lakukan?
Peter Lawrey
2
Hai @PeterLawrey, saya sedang tring untuk mengambil Enum dari publik String publik ObjectType {PERSON ("Person") String parameterName; ObjectType (String parameterName) {this.parameterName = parameterName; } public String getParameterName () {return this.parameterName; } ObjectType statis publik fromString (String parameterName) {if (parameterName! = null) {for (ObjectType objType: ObjectType.values ​​()) {if (parameterName.equalsIgnoreCase (objType.parameterName)) {return objType; }}} return null; }}
Murtaza Kanchwala
35

Di Java 8 atau lebih baru, menggunakan Streaming :

public enum Blah
{
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;

    Blah(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public static Optional<Blah> fromText(String text) {
        return Arrays.stream(values())
          .filter(bl -> bl.text.equalsIgnoreCase(text))
          .findFirst();
    }
}
Hans Schreuder
sumber
Tidak yakin ini entah bagaimana jawaban yang lebih baik. Streaming dalam hal ini adalah iterator single-threaded seperti yang lainnya atas semua nilai dan bisa dibilang lebih sedikit performanya daripada impl lookup peta. Streaming memiliki nilai lebih dalam konteks multi-utas di mana, misalnya, eksekusi paralel file teks yang dipisahkan dengan baris baru dapat meningkatkan kinerja.
Darrell Teague
28

Jika Anda tidak ingin menulis utilitas sendiri, gunakan Google Perpustakaan:

Enums.getIfPresent(Blah.class, "A")

Tidak seperti fungsi java yang ada di dalamnya, mari kita periksa apakah A ada dalam Blah dan tidak melempar pengecualian.

Andrejs
sumber
7
bagian yang menyedihkan adalah, ini mengembalikan google Opsional dan bukan java Opsional
javaProgrammer
Benar. Meskipun dikecualikan. Google dan Netflix memiliki lib Java yang luar biasa. Di mana ada tumpang tindih dengan Java catch-up class yang diimplementasikan dalam versi yang lebih baru pasti menyebabkan masalah. Jenis harus semua dalam satu lib vendor.
Darrell Teague
26

2 sen saya di sini: menggunakan Java8 Streams + memeriksa string yang tepat:

public enum MyEnum {
    VALUE_1("Super"),
    VALUE_2("Rainbow"),
    VALUE_3("Dash"),
    VALUE_3("Rocks");

    private final String value;

    MyEnum(String value) {
        this.value = value;
    }

    /**
     * @return the Enum representation for the given string.
     * @throws IllegalArgumentException if unknown string.
     */
    public static MyEnum fromString(String s) throws IllegalArgumentException {
        return Arrays.stream(MyEnum.values())
                .filter(v -> v.value.equals(s))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("unknown value: " + s));
    }
}

** EDIT **

Berganti nama fungsinya fromString()sejak menamainya menggunakan konvensi itu, Anda akan memperoleh beberapa manfaat dari bahasa Java itu sendiri; sebagai contoh:

  1. Konversi langsung jenis di anotasi HeaderParam
Manu
sumber
1
Sebagai alternatif untuk memungkinkan Anda menulis switchblok yang lebih mudah dibaca , Anda bisa .orElse(null)sebagai ganti .orElseThrow()sehingga Anda bisa membuat kode pengecualian lemparan dalam defaultklausa - dan memasukkan info yang lebih berguna saat dibutuhkan. Dan untuk membuatnya lebih ringan Anda bisa menggunakanv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Adam
atau hanya mengembalikan Optionaldari findFirst(), yang memungkinkan pengguna untuk memutuskan apakah dia mau .orElse(null), orElseThrow()atau apa pun ....
user85421
1
Mendeklarasikan public static MyEnum valueOf(String)sebenarnya adalah kesalahan kompilasi, karena itu sama dengan yang didefinisikan secara implisit, jadi versi lama dari jawaban Anda sebenarnya lebih baik. ( JLS , ideone )
Radiodef
Dalam opsi saya, lebih baik menghindari Pengecualian dan menggunakan Opsional. Di samping itu kita harus membatalkan null dan menggunakan Opsional juga.
Hans Schreuder
Sekali lagi, ingatlah bahwa meskipun kode yang kurang atau lebih baik ... implementasi Stream seperti ini hanyalah sebuah iterator atas semua nilai versus pencarian peta (less performant).
Darrell Teague
16

Anda mungkin perlu ini:

public enum ObjectType {
    PERSON("Person");

    public String parameterName;

    ObjectType(String parameterName) {
        this.parameterName = parameterName;
    }

    public String getParameterName() {
        return this.parameterName;
    }

    //From String method will return you the Enum for the provided input string
    public static ObjectType fromString(String parameterName) {
        if (parameterName != null) {
            for (ObjectType objType : ObjectType.values()) {
                if (parameterName.equalsIgnoreCase(objType.parameterName)) {
                    return objType;
                }
            }
        }
        return null;
    }
}

Satu Tambahan Lagi:

   public static String fromEnumName(String parameterName) {
        if (parameterName != null) {
            for (DQJ objType : DQJ.values()) {
                if (parameterName.equalsIgnoreCase(objType.name())) {
                    return objType.parameterName;
                }
            }
        }
        return null;
    }

Ini akan mengembalikan Anda Nilai oleh Nama Enum yang Dimodifikasi untuk misalnya jika Anda memberikan "PERSON" di fromEnumName, itu akan mengembalikan Anda Nilai Enum yaitu "Orang"

Murtaza Kanchwala
sumber
13

Cara lain untuk melakukan ini dengan menggunakan metode statis implisit name()Enum. nama akan mengembalikan string yang tepat digunakan untuk membuat enum yang dapat digunakan untuk memeriksa terhadap string yang disediakan:

public enum Blah {

    A, B, C, D;

    public static Blah getEnum(String s){
        if(A.name().equals(s)){
            return A;
        }else if(B.name().equals(s)){
            return B;
        }else if(C.name().equals(s)){
            return C;
        }else if (D.name().equals(s)){
            return D;
        }
        throw new IllegalArgumentException("No Enum specified for this string");
    }
}

Pengujian:

System.out.println(Blah.getEnum("B").name());

//it will print B  B

inspirasi: 10 Contoh Enum di Jawa

Vikram
sumber
7
Ini pada dasarnya apa yang valueOfAnda lakukan. Metode statis ini tidak menawarkan tambahan apa pun, kecuali semua. Maka konstruksi if / else sangat berbahaya ... konstanta enum baru yang ditambahkan akan menyebabkan metode ini rusak tanpa perubahan.
YoYo
Pertimbangkan juga contoh ini tentang bagaimana kita dapat menggunakan valueOf untuk melakukan pencarian kasus yang tidak sensitif, atau bagaimana kita dapat menghindari pengecualian itu dan menggunakan alias untuk memberikan nama alternatif: stackoverflow.com/a/12659023/744133
YoYo
2
name()tidak statis.
nrubin29
10

Solusi menggunakan perpustakaan Guava. Metode getPlanet () bersifat case-sensitive, jadi getPlanet ("MerCUrY") akan mengembalikan Planet.MERCURY.

package com.universe.solarsystem.planets;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Enums;
import com.google.common.base.Optional;

//Pluto and Eris are dwarf planets, who cares!
public enum Planet {
   MERCURY,
   VENUS,
   EARTH,
   MARS,
   JUPITER,
   SATURN,
   URANUS,
   NEPTUNE;

   public static Planet getPlanet(String name) {
      String val = StringUtils.trimToEmpty(name).toUpperCase();
      Optional <Planet> possible = Enums.getIfPresent(Planet.class, val);
      if (!possible.isPresent()) {
         throw new IllegalArgumentException(val + "? There is no such planet!");
      }
      return possible.get();
   }
}
javabrew
sumber
8

Untuk menambah jawaban sebelumnya, dan membahas beberapa diskusi seputar nol dan NPE, saya menggunakan Pilihan Guava untuk menangani kasus yang tidak ada / tidak valid. Ini berfungsi baik untuk penguraian parameter / URI.

public enum E {
    A,B,C;
    public static Optional<E> fromString(String s) {
        try {
            return Optional.of(E.valueOf(s.toUpperCase()));
        } catch (IllegalArgumentException|NullPointerException e) {
            return Optional.absent();
        }
    }
}

Bagi mereka yang tidak sadar, inilah beberapa info lebih lanjut tentang menghindari null dengan Opsional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional

tom
sumber
Ini adalah jawaban yang sangat bagus untuk pola terkait dan penggunaan Opsional di dalam Enum - meningkatkan fakta bahwa Enum juga kelas dan dengan demikian dapat didekorasi dengan metode, mengganti metode, dll. Ini adalah kasus yang baik untuk pemrograman gaya Fluent juga karena null yang dikembalikan dari metode membuat konstruk buggy (NPE di tempat yang tidak diketahui di rantai panggilan metode Fluent).
Darrell Teague
8

Di Java 8, pola Peta statis bahkan lebih mudah dan merupakan metode pilihan saya. Jika Anda ingin menggunakan Enum dengan Jackson, Anda dapat mengganti ke Strtring dan menggunakan itu alih-alih nama, lalu anotasi dengan@JsonValue

public enum MyEnum {
    BAR,
    BAZ;
    private static final Map<String, MyEnum> MAP = Stream.of(MyEnum.values()).collect(Collectors.toMap(Enum::name, Function.identity()));
    public static MyEnum fromName(String name){
        return MAP.get(name);
    }
}

public enum MyEnumForJson {
    BAR("bar"),
    BAZ("baz");
    private static final Map<String, MyEnumForJson> MAP = Stream.of(MyEnumForJson.values()).collect(Collectors.toMap(Object::toString, Function.identity()));
    private final String value;

    MyEnumForJson(String value) {
        this.value = value;
    }

    @JsonValue
    @Override
    public String toString() {
        return value;
    }

    public static MyEnumForJson fromValue(String value){
        return MAP.get(value);
    }
}
Novaterata
sumber
Jackson adalah implementasi JSON (Notasi Obyek JavaScript). Pertanyaan aslinya tidak ada hubungannya dengan JSON.
Darrell Teague
Bagian JSON hanyalah bonus yang saya temukan relevan pada saat itu, karena mendapatkan Enum dari string pada dasarnya adalah jenis deserialisasi dan JSON / Jackson mungkin merupakan solusi serialisasi yang paling populer.
Novaterata
Memahami tetapi dari aspek moderasi - itu tidak berkontribusi untuk menjawab pertanyaan OP jadi hanya mencoba untuk membantu mengatur konteks di sana. JSON memang cara untuk mengubah objek menjadi bentuk kanonik di Jawa dengan Jackson menjadi perpustakaan yang hebat.
Darrell Teague
6
public static MyEnum getFromValue(String value) {
    MyEnum resp = null;
    MyEnum nodes[] = values();
    for(int i = 0; i < nodes.length; i++) {
        if(nodes[i].value.equals(value)) {
            resp = nodes[i];
            break;
        }
    }
    return resp;
}
Prasobh.Kollattu
sumber
lihat tautan ini untuk panduan tentang menjawab dan mengajukan pertanyaan di stackoverflow.com: stackoverflow.com/faq
bakoyaro
1
Itu kurang lebih sama dengan jawaban JoséMi
Rup
6

O (1) metode yang diilhami dari kode yang dihasilkan hemat yang memanfaatkan hashmap.

public enum USER {
        STUDENT("jon",0),TEACHER("tom",1);

        private static final Map<String, Integer> map = new HashMap<>();

        static {
                for (USER user : EnumSet.allOf(USER.class)) {
                        map.put(user.getTypeName(), user.getIndex());
                }
        }

        public static int findIndexByTypeName(String typeName) {
                return map.get(typeName);
        }

        private USER(String typeName,int index){
                this.typeName = typeName;
                this.index = index;
        }
        private String typeName;
        private int index;
        public String getTypeName() {
                return typeName;
        }
        public void setTypeName(String typeName) {
                this.typeName = typeName;
        }
        public int getIndex() {
                return index;
        }
        public void setIndex(int index) {
                this.index = index;
        }

}
Sisyphus
sumber
Perhatikan bahwa nol (0) dan satu (1) pengidentifikasi tidak perlu. Metode Enum values ​​() akan mengembalikan anggota dalam urutan yang sama dengan kode. Dengan demikian entri pertama akan menjadi nol, yang kedua, dll.
Darrell Teague
6

Enum sangat berguna, saya telah menggunakan Enumbanyak untuk menambahkan deskripsi untuk beberapa bidang dalam bahasa yang berbeda, sebagai contoh berikut:

public enum Status {

    ACT(new String[] { "Accepted", "مقبول" }),
    REJ(new String[] { "Rejected", "مرفوض" }),
    PND(new String[] { "Pending", "في الانتظار" }),
    ERR(new String[] { "Error", "خطأ" }),
    SNT(new String[] { "Sent", "أرسلت" });

    private String[] status;

    public String getDescription(String lang) {
        return lang.equals("en") ? status[0] : status[1];
    }

    Status(String[] status) {
        this.status = status;
    }
}

Dan kemudian Anda dapat mengambil deskripsi secara dinamis berdasarkan kode bahasa yang diteruskan ke getDescription(String lang)metode, misalnya:

String statusDescription = Status.valueOf("ACT").getDescription("en");
Ebraheem Alrabee '
sumber
1
Contoh yang baik dengan mendorong Enums lebih jauh. Akan membuat pengkodean bahasa menggunakan nama statis standar dan pencarian di Peta tetapi masih ... contoh yang baik untuk memiliki enum dengan tag berbeda untuk apa yang pada dasarnya adalah nilai logis yang sama.
Darrell Teague
5

Bagaimana dengan?

public enum MyEnum {
    FIRST,
    SECOND,
    THIRD;

    public static Optional<MyEnum> fromString(String value){
        try{
            return Optional.of(MyEnum.valueOf(value));
        }catch(Exception e){
            return Optional.empty();
        }
    }
}
DCO
sumber
4

java.lang.Enum mendefinisikan beberapa metode yang berguna, yang tersedia untuk semua tipe enumerasi di Jawa:

  • Kamu bisa menggunakan name() metode untuk mendapatkan nama konstanta Enum. String literal yang digunakan untuk menulis konstanta enum adalah nama mereka.
  • Demikian pula values() metode dapat digunakan untuk mendapatkan array dari semua konstanta Enum dari jenis Enum.
  • Dan untuk pertanyaan yang diajukan, Anda dapat menggunakan valueOf()metode untuk mengubah sembarang String ke konstanta Enum di Jawa, seperti yang ditunjukkan di bawah ini.
public class EnumDemo06 {
    public static void main(String args[]) {
        Gender fromString = Gender.valueOf("MALE");
        System.out.println("Gender.MALE.name() : " + fromString.name());
    }

    private enum Gender {
        MALE, FEMALE;
    }
}

Output:
Gender.MALE.name() : MALE

Dalam cuplikan kode ini, valueOf()metode mengembalikan Gender.MALE konstanta Enum, memanggil nama yang mengembalikan "MALE".

KNU
sumber
4

Pustaka commons-lang Apache memiliki fungsi statis org.apache.commons.lang3.EnumUtils.getEnum yang akan memetakan sebuah String ke tipe Enum Anda. Jawaban yang sama pada dasarnya sama dengan Geoffrey tetapi mengapa menggulung sendiri saat sudah ada di luar sana.

pjklauser
sumber
1
Komentar wajar (KERING) tetapi ... sementara sebagian besar hal-hal Apache Commons hebat, saya telah menemukan beberapa bug dan anti-pola sendiri di pangkalan itu. Dengan demikian merujuk pada mengatakan implementasi Joshua Bloch mungkin lebih kuat. Turun kemudian harus meninjau kode Apache untuk mengetahui apa yang diterapkan seseorang. Jika dikatakan Doug Leah yang terkenal yang menulis ulang Java concurrency ... maka saya akan mempercayainya secara implisit.
Darrell Teague
4

Menambahkan ke jawaban berperingkat teratas, dengan utilitas bermanfaat ...

valueOf() melempar dua Pengecualian berbeda dalam kasus di mana ia tidak suka inputnya.

  • IllegalArgumentException
  • NullPointerExeption

Jika persyaratan Anda sedemikian rupa sehingga Anda tidak memiliki jaminan bahwa String Anda pasti akan cocok dengan nilai enum, misalnya jika data String berasal dari database dan dapat berisi versi lama dari enum, maka Anda harus menangani ini sering...

Jadi, inilah metode yang dapat digunakan kembali yang saya tulis yang memungkinkan kita untuk mendefinisikan Enum default untuk dikembalikan jika String yang kita lewati tidak cocok.

private static <T extends Enum<T>> T valueOf( String name , T defaultVal) {
        try {
            return Enum.valueOf(defaultVal.getDeclaringClass() , name);
        } catch (IllegalArgumentException | NullPointerException e) {
            return defaultVal;
        }
    }

Gunakan seperti ini:

public enum MYTHINGS {
    THINGONE,
    THINGTWO
}

public static void main(String [] asd) {
  valueOf("THINGTWO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGTWO
  valueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE
}
tombak
sumber
2

Karena versi switch-belum disebutkan saya memperkenalkannya (menggunakan kembali enum OP):

  private enum Blah {
    A, B, C, D;

    public static Blah byName(String name) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          throw new IllegalArgumentException(
            "No enum constant " + Blah.class.getCanonicalName() + "." + name);
      }
    }
  }

Karena ini tidak memberikan nilai tambahan pada valueOf(String name)metode, masuk akal untuk mendefinisikan metode tambahan jika kita ingin memiliki perilaku yang berbeda. Jika kami tidak ingin menaikkan, IllegalArgumentExceptionkami dapat mengubah implementasinya menjadi:

  private enum Blah {
    A, B, C, D;

    public static Blah valueOfOrDefault(String name, Blah defaultValue) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          if (defaultValue == null) {
            throw new NullPointerException();
          }
          return defaultValue;
      }
    }
  }

Dengan memberikan nilai default, kami menjaga kontrak dari Enum.valueOf(String name)tanpa melemparkan sebuah IllegalArgumentException cara bahwa dalam kasus tidak nulldikembalikan. Oleh karena itu kami melempar NullPointerExceptionjika nama adalah nulldan defaultjika defaultValueada null. Begitulah cara valueOfOrDefaultkerjanya.

Pendekatan ini mengadopsi desain Map-Interface yang menyediakan metode Map.getOrDefault(Object key, V defaultValue)pada Java 8.

LuCio
sumber
1

Utilitas lain menangkap dengan cara terbalik. Menggunakan nilai yang mengidentifikasi Enum itu, bukan dari namanya.

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.EnumSet;

public class EnumUtil {

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose a 
     * public method return value of this Enum is 
     * equal to <code>valor</code>.<br/>
     * Such method should be unique public, not final and static method 
     * declared in Enum.
     * In case of more than one method in match those conditions
     * its first one will be chosen.
     * 
     * @param enumType
     * @param value
     * @return 
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value) {
        String methodName = getMethodIdentifier(enumType);
        return from(enumType, value, methodName);
    }

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose  
     * public method <code>methodName</code> return is 
     * equal to <code>value</code>.<br/>
     *
     * @param enumType
     * @param value
     * @param methodName
     * @return
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value, String methodName) {
        EnumSet<E> enumSet = EnumSet.allOf(enumType);
        for (E en : enumSet) {
            try {
                String invoke = enumType.getMethod(methodName).invoke(en).toString();
                if (invoke.equals(value.toString())) {
                    return en;
                }
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    private static String getMethodIdentifier(Class<?> enumType) {
        Method[] methods = enumType.getDeclaredMethods();
        String name = null;
        for (Method method : methods) {
            int mod = method.getModifiers();
            if (Modifier.isPublic(mod) && !Modifier.isStatic(mod) && !Modifier.isFinal(mod)) {
                name = method.getName();
                break;
            }
        }
        return name;
    }
}

Contoh:

public enum Foo {
    ONE("eins"), TWO("zwei"), THREE("drei");

    private String value;

    private Foo(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

EnumUtil.from(Foo.class, "drei")kembali Foo.THREE, karena akan digunakan getValueuntuk mencocokkan "drei", yang merupakan publik yang unik, bukan metode final dan tidak statis di Foo. Dalam hal Foo memiliki lebih dari pada metode umum, belum final dan tidak statis, misalnya, getTranslateyang kembali "drei", metode lainnya dapat digunakan: EnumUtil.from(Foo.class, "drei", "getTranslate").

Moesio
sumber
1

Solusi Kotlin

Buat ekstensi lalu panggil valueOf<MyEnum>("value"). Jika jenisnya tidak valid, Anda akan mendapatkan nol dan harus menanganinya

inline fun <reified T : Enum<T>> valueOf(type: String): T? {
    return try {
        java.lang.Enum.valueOf(T::class.java, type)
    } catch (e: Exception) {
        null
    }
}

Atau, Anda dapat menetapkan nilai default, menelepon valueOf<MyEnum>("value", MyEnum.FALLBACK), dan menghindari respons nol. Anda dapat memperluas enum spesifik Anda agar default menjadi otomatis

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
    return try {
        java.lang.Enum.valueOf(T::class.java, type)
    } catch (e: Exception) {
        default
    }
}

Atau jika Anda ingin keduanya, buat yang kedua:

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Gibolt
sumber
Apakah Anda pikir jawaban Anda akan memiliki rumah yang lebih baik di sini? stackoverflow.com/questions/28548015/…
nabster
0

Saya suka menggunakan proses semacam ini untuk mem-parsing perintah sebagai string ke enumerasi. Saya biasanya memiliki salah satu enumerasi sebagai "tidak dikenal" sehingga membantu mengembalikannya ketika yang lain tidak ditemukan (bahkan berdasarkan kasus yang tidak sensitif) daripada nol (artinya tidak ada nilai). Karenanya saya menggunakan pendekatan ini.

static <E extends Enum<E>> Enum getEnumValue(String what, Class<E> enumClass) {
    Enum<E> unknown=null;
    for (Enum<E> enumVal: enumClass.getEnumConstants()) {  
        if (what.compareToIgnoreCase(enumVal.name()) == 0) {
            return enumVal;
        }
        if (enumVal.name().compareToIgnoreCase("unknown") == 0) {
            unknown=enumVal;
        }
    }  
    return unknown;
}
John Hemming
sumber
-1

Cara tercepat untuk mendapatkan nama enum adalah dengan membuat peta teks dan nilai enum saat aplikasi dimulai, dan untuk mendapatkan nama panggil fungsi Blah.getEnumName ():

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;
    private HashMap<String, String> map;
    Blah(String text) {
    this.text = text;
    }

    public String getText() {
      return this.text;
    }

    static{
      createMapOfTextAndName();
    }

    public static void createMapOfTextAndName() {
        map = new HashMap<String, String>();
        for (Blah b : Blah.values()) {
             map.put(b.getText(),b.name());
        }
    }
    public static String getEnumName(String text) {
        return map.get(text.toLowerCase());
    } 
}
Bishal Jaiswal
sumber