Java'da bir dize değerinden numaralandırma değeri nasıl alınır?


1984

Diyelim ki bir numaram var

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

ve ben örneğin bir dize enum değeri bulmak istiyoruz "A"olurdu Blah.A. Bunu yapmak nasıl mümkün olabilir?

Enum.valueOf()ihtiyacım yöntemi? Öyleyse, bunu nasıl kullanırım?

Yanıtlar:


2258

Evet, Blah.valueOf("A")sana vereceğim Blah.A.

Vaka dahil olmak üzere adın tam eşleşme olması gerektiğini unutmayın : Blah.valueOf("a")ve Blah.valueOf("A ")her ikisi de bir IllegalArgumentException.

Statik yöntemler valueOf()ve values()derleme zamanında oluşturulur ve kaynak kodunda görünmez. Yine de Javadoc'ta ortaya çıkıyorlar; örneğin, Dialog.ModalityTypeher iki yöntemi de gösterir.


100
Referans olarak, Blah.valueOf("A")yöntem büyük / küçük harfe duyarlıdır ve yabancı boşlukları tolere etmez, bu nedenle aşağıda @ JoséMi tarafından önerilen alternatif çözümdür.
Brett

3
@Michael Myers, Bu cevap şimdiye kadar en çok oy alan olduğundan, bir enum tanımlamanın iyi bir uygulama olduğunu ve String değerinin tam olarak aynı olduğunu anlamalı mıyım?
Kevin Meredith

4
@KevinMeredith: toString()Değeri kastediyorsanız , hayır, bunu söylemezdim. name()geçersiz kılmadığınız sürece enum sabitinin gerçek tanımlı adını alırsınız.
Michael Myers

3
Tam olarak ne demek istiyorsun "derleme zamanında oluşturulur ve kaynak kodunda görünmez." ?
treesAreEverywhere

8
@treesAreEverywhere Daha spesifik olarak, bu yöntemler derleyici tarafından oluşturulur (veya sentezlenir ). Gerçek enum Blah {...}tanım kendi beyan çalışmamalıdır valuesne de valuesOf. Aslında "sınıf" üye değişkeni bildirmemiş olsanız bile "AnyTypeName.class" yazabilirsiniz. derleyici hepsini Just Work yapar. (Bu yanıt artık 3 ay sonra sizin için yararlı olmayabilir, ancak her ihtimale karşı.)
Ti Strga

864

Metin numaralandırma değeriyle aynı değilse başka bir çözüm:

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

396
throw new IllegalArgumentException("No constant with text " + text + " found")daha iyi olurdu return null.
whiskysierra

8
@whiskeysierra Jon Skeet buna katılmayacaktı. stackoverflow.com/questions/1167982/…
Sanghyun Lee

11
@Sangdol Could Eğer dönen boş neden daha iyi olduğunu bize enlight?
whiskysierra

57
@Sangdol genellikle SUN'un - oops - Oracle'ın aynı durumda ne yaptığını kontrol etmek iyi bir şeydir. Ve Enum.valueOf () o gösteriyor IS bu durumda bir özel durum atmak için en iyi yöntem. Çünkü bu istisnai bir durum. "Performans optimizasyonu" okunamayan kod yazmak için kötü bir bahane ;-)
raudi

5
Peki, "okunabilir" yapmak için @Nullable ek açıklamadan da yararlanabilirsiniz ;-)
JoséMi

121

İşte kullandığım şık bir yardımcı program:

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

Sonra benim enum sınıfta genellikle bazı yazarak kaydetmek için bu var:

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

Numaralandırmalarınızın tamamı büyük harf değilse, Enum.valueOfsatırı değiştirin .

Çok kötü kullanamazsınız T.classiçin Enum.valueOfolarak Tsilinir.


176
Bu boş av bloğu beni gerçekten deli ediyor, üzgünüm.
whiskysierra

32
@LazloBonin: İstisnalar kontrol akışı için değil istisnai durumlar içindir. Kendinize Etkili Java'nın bir kopyasını alın .
Monica'yı eski durumuna getirin - M. Schröder

10
Kullanmak istediğiniz Java API bir istisna atarsa ​​ve kodunuzun bir tane atmasını istemiyorsanız, istisnayı böyle yutabilir veya mantığı sıfırdan yeniden yazabilirsiniz, böylece ilk etapta istisna atılmaz. İstisnayı yutmak genellikle daha az kötülüktür.
Nate CK

47
Korkunç! Her zaman, bunları ele alabileceğiniz istisnaları daima yakalayın. Yukarıdaki örnek, bunu YAPMAYIN için mükemmel bir örnektir . Neden? Bu yüzden NULL döndürür ve arayan NULL'a karşı kontrol etmek veya bir NPE atmak zorundadır. Arayan kişi durumun nasıl ele alınacağını biliyorsa, eğer if-try-catch yapmak biraz daha zarif görünebilir, ancak idare edemezse tekrar null geçmesi gerekir ve arayan arayan tekrar NULL'a karşı kontrol etmelidir , vb.
raudi

10
Yukarıdaki çözüm için adil olmak gerekirse, IllegalArgumentException öğesini atmak ve programınızın akışını kırmak yerine null döndürmenizi gerektiren durumlar vardır, örneğin, bir web hizmeti şeması ile her zaman bir olmayan bir veritabanı şeması arasındaki sıralamaları eşleme -birine. Ancak, yakalama bloğunun asla boş bırakılmaması gerektiğine katılıyorum. Log.warn veya izleme amaçlı bir şey koyun.
Adrian M

101

Etkili Java Joshua Bloch'un desenini kullanın :

(kısalık için basitleştirilmiş)

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

Ayrıca bakınız:

Enum ve Map eşlemelerini kullanan Oracle Java Örneği

Enum türündeki statik blokların yürütme sırası

Java numaralandırmasını Dize değerinden nasıl arayabilirim?


4
eğer Joshua Bloch söylerse o zaman bu gitmek için tek yoldur :-). Her zaman burada aşağı kaydırmak zorunda bir utanç.
dermoritz

11
Bu, Java 8'de yapabileceğiniz gibi daha da basittir: Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))Ayrıca toString () (yapıcıdan geçirilir) geçersiz kılmayı ve ad yerine bunu kullanmanızı öneririz, özellikle Enum serileştirilebilir verilerle ilişkiliyse, bu, kasayı vermeden kontrol etmenizi sağlar Sonar uygun.
Novaterata

1
Java 8, bu forumdaki birçok (daha iyi) yanıtı kesinlikle değiştirebilir / değiştirecektir. Hiç kuyruk (Sonar) köpek (uygulama kodu) olsa wag sahip olduğundan emin değilim.
Darrell Teague

3
Eğer unmodifiableMapyine de koyacaksanız , a ile başlamanın bir yararı yoktur ConcurrentHashMap. Sadece a HashMap. (Guava's varsa ImmutableMapo zaman bunu tavsiye ederim!)
Daniel Pryden

9
Statik başlatma doğal olarak senkronize edilir , bu nedenle ConcurrentHashMapharitanın başlatmadan sonra asla değiştirilmediği burada kullanmak için kesinlikle hiçbir neden yoktur . Bu nedenle, örneğin, JLS'deki örneğin kendisi bile bir düzenli kullanır HashMap.
Radiodef

74

Davanıza da dikkat etmelisiniz. Açıklamama izin verin: Blah.valueOf("A")işler yapmak ama Blah.valueOf("a")işe yaramayacak. Sonra tekrar Blah.valueOf("a".toUpperCase(Locale.ENGLISH))işe yarar.

düzenlemek
Changed toUpperCaseto toUpperCase(Locale.ENGLISH)based on tc. yorum ve java belgeleri

edit2 sitesinde kullanmalısınız android Locale.USgibi Sulai işaret .


6
Varsayılan yerel ayara karşı dikkatli olun!
tc.

3
Orada Android kullanıcıları için, Android belgelerininLocale.US makine tarafından okunabilen giriş / çıkış kullanımını açıkça teşvik ettiğini belirtmek isterim .
sulai

2
@Trengot Evet, ne yazık ki. Türkiye buna iyi bir örnek. Bunu Java'nın varsayılan karakter kümelerinin kırık işlemesi ile birleştirin (varsayılan olarak Unicode yerine Windows'ta Latince'dir) ve bir karakter kümesi veya yerel ayarı kabul eden yöntemlerin varsayılan sürümlerini kullanmanın neredeyse her zaman güvenli olmadığını görürsünüz. Neredeyse her zaman bunları açıkça tanımlamanız gerekir.
Stijn de Witt

Java'nın "varsayılan" karakter kümelerinin ve "kendi başına" bozulduğundan emin olunur, ancak geçersiz kılmalar yerine UTF-8'e varsayılan olarak (her zaman açık olması gerekir) varsayılan olarak anlaşılamayan genç programcılar için daha iyi sistemler olurdu karakter kümesi kavramları.
Darrell Teague

38

İşte herhangi bir Enum için bunu yapabilen ve büyük / küçük harfe duyarlı olmayan bir yöntem.

/** 
 * 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()
    ));
}

Bu varyasyon doğru bir şekilde yapıyor: equalsIgnoreCasegidilecek yol. +1
Stijn de Witt

Büyük / küçük harf duyarsızlığı gibi ... anahtarları ve ... minör için dize atamalarını (rastgele) tercih eder, ancak yineleme bu tür repetatif bir arama için daha az performans gösterir. Bu nedenle EnumMap ve ark.
Darrell Teague

Bu çalışmıyor ! Amacım için equalsIgnoreCase öğesini eşit olarak değiştirdim. Her iki eşit giriş de tamamen aynı olmasına rağmen kod başarısız oldu.
MasterJoe2

36

Kullanmak Blah.valueOf(string)en iyisidir ancak siz de kullanabilirsiniz Enum.valueOf(Blah.class, string).


1
Büyük / küçük harfe duyarlı, yardım etmiyor!
Murtaza Kanchwala

@MurtazaKanchwala Yorumunuzu netleştirebilir misiniz? Ne yapmaya çalışıyorsun?
Peter Lawrey

2
Merhaba @PeterLawrey, ben bir String genel enum ObjectType {PERSON ("Kişi") genel String parametreAdı bir Enum getirmek için tring oldu; ObjectType (String parametreName) {this.parameterName = parametreAdı; } public String getParameterName () {return this.parameterName; } public static ObjectType fromString (String parametreName) {if (parametreAdı! = null) {for (ObjectType objType: ObjectType.values ​​()) {if (parametreName.equalsIgnoreCase (objType.parameterName)) {return objType; }}} döndür null; }}
Murtaza Kanchwala

34

Java 8 veya sonraki sürümlerde, Akışları kullanarak :

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

Bunun bir şekilde daha iyi olduğuna emin değilim. Bu durumda akışlar, diğer tüm değerlerde olduğu gibi tek iş parçacıklı bir yineleyicidir ve bir harita arama impl'sinden muhtemelen daha az performans gösterir. Akışlar çok iş parçacıklı bir bağlamda, örneğin satırsonu ile ayrılmış bir metin dosyasının paralel yürütülmesinin performansı artırabileceği daha fazla değere sahiptir.
Darrell Teague

28

Kendi yardımcı programınızı yazmak istemiyorsanız Google'ın kütüphane:

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

Dahili java fonksiyonunun aksine, A'nın Blah'ta mevcut olup olmadığını ve bir istisna atmadığını kontrol edelim.


7
üzgün kısmı, bu bir google İsteğe bağlı döndürür ve java değil İsteğe bağlı
javaProgrammer

Doğru. Gerçi. Google ve Netflix'in harika Java kütüphaneleri vardır. Daha yeni sürümlerde uygulanan Java catch-up sınıfları ile çakışma olduğunda kaçınılmaz olarak soruna neden olur. Tür hepsi bir satıcı lib üzerinde olması gerekir.
Darrell Teague

26

Buradaki 2 sentim: Java8 Streams + kullanarak tam bir dizeyi kontrol etmek:

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

** DÜZENLE **

fromString()Bu kuralı kullanarak adlandırdığından beri işlevi yeniden adlandırdığından, Java dilinin kendisinden bazı avantajlar elde edersiniz; Örneğin:

  1. HeaderParam ek açıklamasında türlerin doğrudan dönüştürülmesi

1
Alternatif daha okunabilir yazmak için izin vermek switch, bloklar yapabilirsiniz .orElse(null)yerine .orElseThrow()sen istisna atmak kod böylece defaultfıkra - ve gerektiğinde daha yararlı bilgiler içerir. Ve daha yumuşak kullanabilmek içinv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Adam

ya da sadece iade Optionalgelen findFirst()isterse kullanıcı karar verme olanağı sağlayacak, .orElse(null), orElseThrow()ya da her türlü ....
user85421

1
A bildirimi public static MyEnum valueOf(String)aslında bir derleme hatasıdır, çünkü örtük olarak tanımlanmış olanla aynıdır, bu nedenle cevabınızın eski sürümü aslında daha iyidir. ( Jls , ideone )
Radiodef

Benim seçeneğimde İstisnalardan kaçınmak ve İsteğe Bağlı kullanmak daha iyidir. Bunun yanında null değeri geçersiz kılmalı ve bunun yerine Opsiyonel'i de kullanmalıyız.
Hans Schreuder

Yine, daha az veya daha iyi görünen kod olsa bile ... bunun gibi bir Akış uygulamasının, bir harita aramasına (daha az performans) karşı tüm değerler üzerinde bir yineleyici olduğunu unutmayın.
Darrell Teague

16

Buna ihtiyacınız olabilir:

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

Bir Ek Daha:

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

Bu size Değerli Bir Numaralandırma Adıyla Değer döndürür. Örneğin, fromEnumName öğesinde "PERSON" sağlarsanız, size Enum Değeri yani "Kişi" değerini döndürür.


13

Bunu name(), Enum'un örtük statik yöntemini kullanarak yapmanın başka bir yolu . name, belirtilen dizeyi denetlemek için kullanılabilen bu numaralandırmayı oluşturmak için kullanılan dizeyi tam olarak döndürür:

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

Test yapmak:

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

//it will print B  B

ilham: Java'da 10 Numaralandırma Örneği


7
Bu aslında valueOfsizin için ne yapar. Bu statik yöntem ekstra bir şey sunmaz, istisna ve hepsi. Daha sonra if / else yapıları son derece tehlikelidir ... eklenen yeni enum sabiti bu yöntemin değişmeden kırılmasına neden olur.
YoYo

Ayrıca, büyük / küçük harfe duyarlı olmayan bir arama yapmak için valueOf'u nasıl kullanabileceğimizi veya istisnadan nasıl kaçınabileceğimizi ve alternatif adlar sağlamak için takma adları nasıl kullanabileceğimizi de göz önünde bulundurun: stackoverflow.com/a/12659023/744133
YoYo

2
name()statik değildir.
nrubin29

10

Guava kütüphanelerini kullanarak çözüm. GetPlanet () yöntemi büyük / küçük harfe duyarlı değildir, bu nedenle getPlanet ("MerCUrY") Planet.MERCURY öğesini döndürür.

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

8

Önceki yanıtlara eklemek ve null'lar ve NPE ile ilgili tartışmalardan bazılarını ele almak için, yok / geçersiz vakaları ele almak için Guava Seçeneklerini kullanıyorum. Bu, URI / parametre ayrıştırma için harika çalışır.

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

Farkında olmayanlar için, İsteğe Bağlı ile null değerinden kaçınmaya ilişkin daha fazla bilgi bulabilirsiniz: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional


Bu, ilgili kalıplar ve İsteğe bağlı bir Enum içinde kullanımı için gerçekten iyi bir cevaptır - Numaraların da sınıflar olduğu ve böylece yöntemlerle, geçersiz kılma yöntemleriyle vb. yöntemlerden döndürülen null değerleri bu aracı yapar (yöntem çağrılarının Akıcı zincirlerinde bilinmeyen yerlerde NPE).
Darrell Teague

8

Java 8'de statik Harita deseni daha da kolaydır ve benim tercih ettiğim yöntemdir. Enum'u Jackson ile birlikte kullanmak istiyorsanız, toString'i geçersiz kılabilir ve ad yerine bunu kullanabilirsiniz, ardından açıklama ekleyin@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);
    }
}

Jackson bir JSON (JavaScript Nesne Notasyonu) uygulamasıdır. Orijinal sorunun JSON ile ilgisi yoktu.
Darrell Teague

JSON kısmı, o anda alakalı bulduğum bonus şeylerdi, çünkü bir dizeden bir Enum elde etmek temelde bir tür serileştirme ve JSON / Jackson muhtemelen en popüler serileştirme çözümüdür.
Novaterata

Anlamak ama ılımlı açıdan - OP'nin sorusunu cevaplamaya katkıda bulunmadı, bu yüzden sadece orada bağlam oluşturmaya yardımcı olmaya çalışıyor.JSON gerçekten de nesneleri büyük bir kütüphane olan Java ile kanonik forma dönüştürmenin yoludur.
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;
}

stackoverflow.com adresinde cevaplama ve soru sorma kılavuzları için bu bağlantıya bir göz atın: stackoverflow.com/faq
bakoyaro 9:11

1
Bu az ya da çok JoséMi'nin cevabı ile aynı
Rup

6

O (1) yöntem, bir hashmap kullanan tasarruf kaynaklı koddan esinlenmiştir.

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

}

Sıfır (0) ve bir (1) tanımlayıcıların gereksiz olduğuna dikkat edin. Enum değerleri () yöntemi, üyeleri kodlanmış sırayla döndürür. Böylece ilk giriş sıralı sıfır, ikincisi vb.
Olacaktır

6

Enum çok yararlıdır, Enumaşağıdaki örnekte olduğu gibi farklı dillerdeki bazı alanlara açıklama eklemek için çok şey kullanıyorum :

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

Ardından, getDescription(String lang)yönteme iletilen dil koduna göre açıklamayı dinamik olarak alabilirsiniz, örneğin:

String statusDescription = Status.valueOf("ACT").getDescription("en");

1
Enum'ları daha ileriye taşımak için iyi bir örnek. Bir haritadaki standart statik adları ve aramayı kullanarak dil kodlamasını yapardı ama yine de ... aslında aynı mantıksal değer için farklı etiketlerle bir numaralandırmaya sahip olmanın iyi bir örneği olurdu.
Darrell Teague

5

Ne dersin?

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

4

java.lang.Enum Java'daki tüm numaralandırma türlerinde kullanılabilen birkaç yararlı yöntem tanımlar:

  • name()Herhangi bir Enum sabitinin adını almak için yöntemi kullanabilirsiniz . Enum sabitlerini yazmak için kullanılan dize değişmezi adlarıdır.
  • Benzer şekilde values(), bir Enum türünden tüm Enum sabitlerinin bir dizisini elde etmek için yöntem kullanılabilir.
  • Ve sorulan soru için, valueOf()aşağıda gösterildiği gibi herhangi bir String'i Java'da Enum sabitine dönüştürmek için yöntemi kullanabilirsiniz .
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

Bu kod snippet'inde, valueOf()yöntem Enum sabiti Gender.MALE değerini döndürür ve bu çağrıda çağrı adı döndürür "MALE".


4

Apache'nin commons-lang kütüphanesi, bir String'i Enum türünüzle eşleştirecek statik bir org.apache.commons.lang3.EnumUtils.getEnum işlevine sahiptir . Aslında Geoffreys ile aynı cevap ama neden zaten vahşi doğada kendi kendinize rulo.


1
Adil yorum (KURU) ama ... Apache Commons öğelerinin çoğu harika olsa da, ben bu bazda kendim birkaç hata ve anti-desen buldum. Bu nedenle Joshua Bloch'un uygulanmasının daha güçlü olabileceğini söylemek. Birinin ne yaptığını bilmek için Apache kodunu gözden geçirmek zorunda kalır. Java eşzamanlılığını yeniden yazan ünlü Doug Leah söylenirse ... o zaman dolaylı olarak güvenirdim.
Darrell Teague

4

Yararlı bir yardımcı programla en yüksek puanlı cevaba ekleniyor ...

valueOf() girdisini beğenmediği durumlarda iki farklı İstisna atar.

  • IllegalArgumentException
  • NullPointerExeption

Gereksinimleriniz, String'inizin bir enum değeriyle kesinlikle eşleşeceğine dair bir garantiniz yoksa, örneğin String verileri bir veritabanından geliyorsa ve numaralandırmanın eski sürümünü içeriyorsa, bunları işlemeniz gerekir sıklıkla...

Bu yüzden, yazdığım, geçirdiğimiz String eşleşmediğinde döndürülecek varsayılan bir Enum tanımlamamıza izin veren yeniden kullanılabilir bir yöntem.

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

Şöyle kullanın:

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
}

2

Bir switch-versiyon henüz bahsedilmediğinden ben tanıtmak (OP enum yeniden kullanarak):

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

Bu, valueOf(String name)yönteme herhangi bir ek değer vermediğinden , yalnızca farklı bir davranışa sahip olmak istiyorsak ek bir yöntem tanımlamak mantıklıdır. Bir yükseltmek istemiyorsak IllegalArgumentExceptionuygulamayı şu şekilde değiştirebiliriz:

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

Varsayılan bir değer vererek sözleşmeyi , hiçbir durumda iade Enum.valueOf(String name)edilmeyecek IllegalArgumentExceptionşekilde atmadan saklarız null. Bu nedenle, NullPointerExceptioneğer isim ise nullve olması defaulthalinde defaultValueatarız null. İşte böyle valueOfOrDefaultçalışır.

Bu yaklaşım , Java 8'den itibaren Mapbir yöntem sağlayan -Interface tasarımını benimser Map.getOrDefault(Object key, V defaultValue).


1

Başka bir yardımcı program ters şekilde yakalanıyor. Adından değil, Enum'u tanımlayan bir değer kullanmak.

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

Misal:

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")geri döner Foo.THREE, çünkü getValueFoo'daki nihai değil statik yöntem değil, benzersiz genel olan "drei" ile eşleşir. Durumda Foo daha örneğin, kamu nihai değil ve statik değildir yöntemi, üzerinde daha vardır getTranslatedöner "drei", diğer bir yöntem kullanılabilir: EnumUtil.from(Foo.class, "drei", "getTranslate").


1

Kotlin Çözümü

Bir uzantı oluşturun ve arayın valueOf<MyEnum>("value"). Tür geçersizse, null olur ve ele almanız gerekir

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

Alternatif olarak, çağıran valueOf<MyEnum>("value", MyEnum.FALLBACK)ve boş bir yanıttan kaçınan varsayılan bir değer ayarlayabilirsiniz . Belirli numaralandırmanızı varsayılanın otomatik olması için genişletebilirsiniz

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

Veya ikisini birden istiyorsanız, ikincisini yapın:

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default

Sizce cevabınızın burada daha iyi bir evi olacak mı? stackoverflow.com/questions/28548015/…
nabster

0

Komutları numaralandırmalara dizeler olarak ayrıştırmak için bu tür bir işlemi kullanmayı seviyorum. Ben normalde "bilinmeyen" olarak numaralandırma biri var, bu yüzden (null değeri yoktur) başkaları null (bu durumda duyarsız bir temelde bile) bulunamadığında döndürmek için yardımcı olur. Bu yüzden bu yaklaşımı kullanıyorum.

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

-1

Enum adını almanın en hızlı yolu, uygulama başladığında bir numaralandırma metni ve değeri haritası oluşturmak ve adı almak için Blah.getEnumName () işlevini çağırmaktır:

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());
    } 
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.