Wie erhalte ich einen Aufzählungswert aus einem Zeichenfolgenwert in Java?


1984

Angenommen, ich habe eine Aufzählung, die gerecht ist

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

und ich möchte zum Beispiel den Aufzählungswert eines Strings finden, "A"der wäre Blah.A. Wie wäre das möglich?

Ist das Enum.valueOf()die Methode, die ich brauche? Wenn ja, wie würde ich das verwenden?

Antworten:


2258

Ja, Blah.valueOf("A")werde dir geben Blah.A.

Beachten Sie, dass der Name genau übereinstimmen muss, einschließlich Groß- Blah.valueOf("a")und Kleinschreibung: und Blah.valueOf("A ")beide werfen eine IllegalArgumentException.

Die statischen Methoden valueOf()und values()werden zur Kompilierungszeit erstellt und erscheinen nicht im Quellcode. Sie erscheinen jedoch in Javadoc; Dialog.ModalityTypezeigt zum Beispiel beide Methoden.


100
Als Referenz unterscheidet die Blah.valueOf("A")Methode zwischen Groß- und Kleinschreibung und toleriert keine Leerzeichen, daher die unten von @ JoséMi vorgeschlagene alternative Lösung.
Brett

3
@Michael Myers, Da diese Antwort bei weitem die am meisten gewählte ist, sollte ich verstehen, dass es eine gute Praxis ist, eine Aufzählung und ihren String-Wert so zu definieren, dass sie genau gleich sind?
Kevin Meredith

4
@ KevinMeredith: Wenn du den toString()Wert meinst , nein, das würde ich nicht sagen. name()Sie erhalten den tatsächlich definierten Namen der Enum-Konstante, sofern Sie ihn nicht überschreiben.
Michael Myers

3
Was genau meinen Sie mit "werden zur Kompilierungszeit erstellt und erscheinen nicht im Quellcode". ?
BäumeAreEverywhere

8
@treesAreEverywhere Insbesondere werden diese Methoden vom Compiler generiert (oder synthetisiert ). Die eigentliche enum Blah {...}Definition sollte nicht versuchen, ihre eigene valuesnoch zu deklarieren valuesOf. Es ist so, wie Sie "AnyTypeName.class" schreiben können, obwohl Sie nie eine "class" -Mitgliedsvariable deklariert haben. Der Compiler macht alles einfach. (Diese Antwort kann für Sie 3 Monate später nicht mehr nützlich sein, aber nur für den Fall.)
Ti Strga

864

Eine andere Lösung, wenn der Text nicht mit dem Aufzählungswert übereinstimmt:

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")wäre besser als return null.
Whiskysierra

8
@whiskeysierra Jon Skeet würde dem nicht zustimmen. stackoverflow.com/questions/1167982/…
Sanghyun Lee

11
@ Sangdol Könnten Sie uns erklären, warum es besser ist, null zurückzugeben?
Whiskysierra

57
@ Sangdol Normalerweise ist es eine gute Sache zu überprüfen, was SUN - oops - Oracle in der gleichen Situation tut. Und als Enum.valueOf () zeigt es IST beste Praxis eine Ausnahme in diesem Fall zu werfen. Weil es eine Ausnahmesituation ist. "Leistungsoptimierung" ist eine schlechte Ausrede, um unlesbaren Code zu schreiben
;-)

5
Nun, Sie könnten auch die Annullation @Nullable verwenden, um sie "lesbar" zu machen
;-)

121

Hier ist ein nützliches Dienstprogramm, das ich verwende:

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

Dann habe ich in meiner Enum-Klasse normalerweise Folgendes, um etwas Tippen zu sparen:

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

Wenn Ihre Aufzählungen nicht alle Großbuchstaben sind, ändern Sie einfach die Enum.valueOfZeile.

Schade , kann ich nicht verwenden , T.classfür Enum.valueOfwie Tgelöscht wird.


176
Dieser leere Fangblock macht mich wirklich verrückt, sorry.
Whiskysierra

32
@LazloBonin: Ausnahmen gelten für außergewöhnliche Bedingungen, nicht für den Kontrollfluss. Holen Sie sich eine Kopie von Effective Java .
Monica wieder herstellen - M. Schröder

10
Wenn die Java-API, die Sie verwenden möchten, eine Ausnahme auslöst und Ihr Code keine Ausnahme auslösen soll, können Sie die Ausnahme entweder wie folgt verschlucken oder die Logik von Grund auf neu schreiben, sodass überhaupt keine Ausnahme ausgelöst wird. Das Schlucken der Ausnahme ist oft das geringere Übel.
Nate CK

47
Schrecklich! Immer, immer fangen Ausnahmen , wo man sie umgehen kann. Das obige Beispiel ist ein perfektes Beispiel dafür, wie man es NICHT macht . Warum? Es gibt also NULL zurück und der Aufrufer muss dann gegen NULL prüfen oder eine NPE werfen. Wenn der Anrufer weiß, wie er mit der Situation umgehen soll, sieht es möglicherweise etwas eleganter aus, einen if vs. try-catch durchzuführen. Wenn er dies jedoch nicht kann, muss er erneut null übergeben und der Anrufer des Anrufers muss erneut gegen NULL prüfen , etc. etc.
raudi

10
Um der obigen Lösung gerecht zu werden, gibt es Fälle, in denen Sie null zurückgeben müssen, anstatt IllegalArgumentException auszulösen und den Programmfluss zu unterbrechen, z. B. indem Sie Aufzählungen zwischen einem Webdienstschema und einem Datenbankschema zuordnen, bei denen es sich nicht immer um eins handelt -zu einem. Ich bin jedoch damit einverstanden, dass der Fangblock niemals leer gelassen werden sollte. Geben Sie einen Code wie log.warn oder etwas zum Verfolgen ein.
Adrian M

101

Verwenden Sie das Muster von Joshua Bloch, Effective Java :

(der Kürze halber vereinfacht)

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

Siehe auch:

Oracle Java-Beispiel mit Enum und Map of Instances

Ausführungsreihenfolge von statischen Blöcken in einem Enum-Typ

Wie kann ich eine Java-Enumeration anhand ihres String-Werts nachschlagen?


4
Wenn Joshua Bloch es gesagt hat, ist dies der einzige Weg :-). Es ist eine Schande, dass ich hier immer nach unten scrollen muss.
Dermoritz

11
Dies ist in Java 8 noch einfacher als möglich: Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))Ich empfehle außerdem, toString () (über den Konstruktor übergeben) zu überschreiben und diesen anstelle des Namens zu verwenden, insbesondere wenn die Aufzählung mit serialisierbaren Daten verknüpft ist, da Sie so das Gehäuse steuern können, ohne dies anzugeben Sonar ein Anfall.
Novaterata

1
Java 8 kann / wird sicherlich viele (bessere) Antworten in diesem Forum ändern. Ich bin mir nicht sicher, ob der Schwanz (Sonar) jemals mit dem Hund wedelt (Anwendungscode).
Darrell Teague

3
Wenn Sie es unmodifiableMaptrotzdem in ein setzen wollen, dann hat es keinen Vorteil, mit einem zu beginnen ConcurrentHashMap. Verwenden Sie einfach eine HashMap. (Wenn Sie ImmutableMap
Guaven

9
Die statische Initialisierung ist von Natur aus synchronisiert , daher gibt es hier absolut keinen Grund, sie zu verwenden ConcurrentHashMap, da die Karte nach der Initialisierung niemals geändert wird. Daher verwendet auch zB das Beispiel im JLS selbst eine reguläre HashMap.
Radiodef

74

Sie sollten auch mit Ihrem Fall vorsichtig sein. Lassen Sie mich erklären: Blah.valueOf("A")Arbeiten funktioniert, wird aber Blah.valueOf("a")nicht funktionieren. Dann Blah.valueOf("a".toUpperCase(Locale.ENGLISH))würde wieder funktionieren.

edit
Geändert toUpperCasezu toUpperCase(Locale.ENGLISH)basierend auf tc. Kommentar und die Java-Dokumente

edit2 Auf Android solltest du verwenden Locale.US, wie Sulai betont .


6
Seien Sie vorsichtig mit dem Standardgebietsschema!
tc.

3
Für Sie Android-Benutzer da draußen möchte ich darauf hinweisen, dass die Android-Dokumentation ausdrücklich die Verwendung von Locale.USmaschinenlesbaren Ein- / Ausgaben fördert .
Sulai

2
@Trengot Ja, leider. Die Türkei ist ein gutes Beispiel. Wenn Sie dies mit Javas fehlerhafter Behandlung von Standardzeichensätzen kombinieren (unter Windows standardmäßig Latin anstelle von Unicode), ist es fast immer unsicher, die Standardversionen von Methoden zu verwenden, die einen Zeichensatz oder ein Gebietsschema akzeptieren. Sie sollten sie fast immer explizit definieren.
Stijn de Witt

Ich bin mir nicht sicher, ob Javas "Standard" -Zeichensätze et al. An sich "kaputt" sind, aber zugegebenermaßen hätte die Verwendung von UTF-8 anstelle von Überschreibungen (die immer explizit erfolgen sollten) bessere Systeme für Junior-Programmierer geschaffen, die dies normalerweise nicht verstehen Zeichensatzkonzepte.
Darrell Teague

38

Hier ist eine Methode, die dies für jede Aufzählung tun kann und bei der die Groß- und Kleinschreibung nicht berücksichtigt wird.

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

Diese Variante macht es richtig: equalsIgnoreCaseist der richtige Weg. +1
Stijn de Witt

Wie Groß- und Kleinschreibung, aber ... Enums gegenüber (zufälligen) String-Zuweisungen für Schlüssel bevorzugen und ... Moll, aber Iteration ist für eine solche möglicherweise sich wiederholende Suche weniger performant. Daher implizieren EnumMap et al.
Darrell Teague

Das funktioniert nicht ! Ich habe den equalsIgnoreCase für meinen Zweck in equals geändert. Der Code ist fehlgeschlagen, obwohl beide Eingaben gleich waren.
MasterJoe2

36

Verwenden Blah.valueOf(string)ist am besten, aber Sie können auch verwenden Enum.valueOf(Blah.class, string).


1
Groß- und Kleinschreibung beachten, nicht helfen!
Murtaza Kanchwala

@MurtazaKanchwala Kannst du deinen Kommentar klarstellen? Was versuchst du zu machen?
Peter Lawrey

2
Hallo @PeterLawrey, ich habe versucht, eine Aufzählung aus einer Zeichenfolge abzurufen. Public enum ObjectType {PERSON ("Person") public String parameterName; ObjectType (String parameterName) {this.parameterName = parameterName; } public String getParameterName () {return this.parameterName; } public static ObjectType fromString (String parameterName) {if (parameterName! = null) {for (ObjectType objType: ObjectType.values ​​()) {if (parameterName.equalsIgnoreCase (objType.parameterName)) {return objType; }}} return null; }}
Murtaza Kanchwala

34

In Java 8 oder höher mit Streams :

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

Ich bin mir nicht sicher, ob dies irgendwie eine bessere Antwort ist. Streams sind in diesem Fall ein Single-Threaded-Iterator wie jeder andere über alle Werte hinweg und wahrscheinlich weniger leistungsfähig als ein Map-Lookup-Impl. Streams haben in einem Multithread-Kontext mehr Wert, in dem beispielsweise die parallele Ausführung einer durch Zeilenumbrüche getrennten Textdatei die Leistung verbessern kann.
Darrell Teague

28

Wenn Sie kein eigenes Dienstprogramm schreiben möchten, verwenden Sie das von Google Bibliothek:

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

Im Gegensatz zur integrierten Java-Funktion können Sie überprüfen, ob A in Blah vorhanden ist, und keine Ausnahme auslösen.


7
trauriger Teil ist, dies gibt ein Google zurück Optional und nicht Java Optional
JavaProgrammer

Wahr. Exoected obwohl. Google und Netflix haben großartige Java-Bibliotheken. Wenn es Überschneidungen mit Java-Aufholklassen gibt, die in neueren Versionen implementiert sind, verursacht dies unweigerlich Probleme. Irgendwie muss alles in einem Anbieter lib sein.
Darrell Teague

26

Meine 2 Cent hier: Verwenden von Java8 Streams + Überprüfen einer genauen Zeichenfolge:

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

** BEARBEITEN **

Wenn Sie die Funktion in umbenannt haben, fromString()da Sie sie mit dieser Konvention benannt haben, profitieren Sie von der Java-Sprache selbst. zum Beispiel:

  1. Direkte Konvertierung von Typen in der HeaderParam-Annotation

1
Alternativ können Sie, damit Sie besser lesbare switchBlöcke schreiben können, .orElse(null)stattdessen .orElseThrow()den Ausnahmefall in der defaultKlausel codieren und bei Bedarf weitere nützliche Informationen hinzufügen. Und um es milder zu machen, könnten Sie verwendenv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Adam

oder Rückkehr nur die Optionalaus findFirst(), so dass der Benutzer entscheiden , ob er will .orElse(null), orElseThrow()oder was auch immer ....
user85421

1
Das Deklarieren von a public static MyEnum valueOf(String)ist tatsächlich ein Kompilierungsfehler, da es mit dem implizit definierten identisch ist, sodass die ältere Version Ihrer Antwort tatsächlich besser ist. ( jls , ideone )
Radiodef

In meiner Option ist es besser, Ausnahmen zu vermeiden und Optional zu verwenden. Daneben sollten wir null ungültig machen und stattdessen auch Optional verwenden.
Hans Schreuder

Denken Sie auch hier daran, dass selbst wenn weniger oder besser aussehender Code ... eine Stream-Implementierung wie diese nur ein Iterator über alle Werte im Vergleich zu einer Kartensuche ist (weniger leistungsfähig).
Darrell Teague

16

Möglicherweise benötigen Sie dazu:

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

Noch eine Ergänzung:

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

Dies gibt Ihnen den Wert durch einen Stringified Enum-Namen zurück. Wenn Sie beispielsweise "PERSON" in fromEnumName angeben, erhalten Sie den Wert von Enum, dh "Person".


13

Eine andere Möglichkeit, dies zu tun, ist die implizite statische Methode name()von Enum. name gibt die genaue Zeichenfolge zurück, die zum Erstellen dieser Aufzählung verwendet wurde, mit der die angegebene Zeichenfolge überprüft werden kann:

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

Testen:

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

//it will print B  B

Inspiration: 10 Beispiele für Enum in Java


7
Dies ist im Wesentlichen das, was valueOffür Sie tut. Diese statische Methode bietet keine zusätzlichen Ausnahmen. Dann sind die if / else-Konstrukte sehr gefährlich ... jede neue hinzugefügte Enum-Konstante führt dazu, dass diese Methode ohne Änderung unterbrochen wird.
YoYo

Betrachten Sie auch dieses Beispiel, wie wir valueOf verwenden können, um eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen, oder wie wir die Ausnahme vermeiden und Aliase verwenden können, um alternative Namen bereitzustellen: stackoverflow.com/a/12659023/744133
YoYo

2
name()ist nicht statisch.
Nrubin29

10

Lösung mit Guava-Bibliotheken. Bei der Methode getPlanet () wird die Groß- und Kleinschreibung nicht berücksichtigt, daher gibt getPlanet ("MerCUrY") Planet.MERCURY zurück.

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

Um die vorherigen Antworten zu ergänzen und einige der Diskussionen um Nullen und NPE anzusprechen, verwende ich Guava-Optionen, um fehlende / ungültige Fälle zu behandeln. Dies funktioniert hervorragend für die URI- / Parameteranalyse.

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

Für diejenigen, die es nicht wissen, finden Sie hier weitere Informationen zum Vermeiden von Null mit Optional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional


Dies ist eine wirklich gute Antwort für verwandte Muster und die Verwendung von Optional in einer Aufzählung. Dabei wird die Tatsache genutzt, dass Aufzählungen auch Klassen sind und daher mit Methoden, Überschreibungsmethoden usw. dekoriert werden können. Dies ist auch seitdem ein guter Fall für die Programmierung im Fluent-Stil Von Methoden zurückgegebene Nullen machen diesen Konstrukt fehlerhaft (NPE an unbekannten Stellen in fließenden Ketten von Methodenaufrufen).
Darrell Teague

8

In Java 8 ist das statische Kartenmuster noch einfacher und meine bevorzugte Methode. Wenn Sie die Aufzählung mit Jackson verwenden möchten, können Sie toString überschreiben und diese anstelle des Namens verwenden und dann mit kommentieren@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 ist eine JSON-Implementierung (JavaScript Object Notation). Die ursprüngliche Frage hatte nichts mit JSON zu tun.
Darrell Teague

Der JSON-Teil war nur ein Bonus, den ich damals für relevant hielt, da das Abrufen einer Aufzählung aus einem String im Grunde eine Art Deserialisierung ist und JSON / Jackson wahrscheinlich die beliebteste Serialisierungslösung ist.
Novaterata

Verstehen Sie, aber unter dem Aspekt der Moderation - es hat nicht zur Beantwortung der Frage des OP beigetragen, sondern nur versucht, den Kontext dort festzulegen. JSON ist in der Tat der richtige Weg, um Objekte in Java in kanonische Form zu konvertieren, wobei Jackson eine großartige Bibliothek ist.
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;
}

Werfen Sie
bakoyaro

1
Das ist mehr oder weniger das Gleiche wie JoséMis Antwort
Rup

6

O (1) -Methode, inspiriert von sparsam erzeugtem Code, der eine Hashmap verwendet.

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

}

Beachten Sie, dass die Bezeichner Null (0) und Eins (1) nicht erforderlich sind. Die Methode Enum values ​​() gibt die Mitglieder in derselben Reihenfolge wie codiert zurück. Somit ist der erste Eintrag die Ordnungszahl Null, der zweite usw.
Darrell Teague,

6

Enum ist sehr nützlich. Ich habe Enumviel verwendet, um eine Beschreibung für einige Felder in verschiedenen Sprachen hinzuzufügen, wie im folgenden Beispiel:

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

Anschließend können Sie die Beschreibung dynamisch anhand des an die getDescription(String lang)Methode übergebenen Sprachcodes abrufen , z. B.:

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

1
Gutes Beispiel, um Enums weiter voranzutreiben. Hätte die Sprachcodierung unter Verwendung der statischen Standardnamen und der Suche in einer Map vorgenommen, aber immer noch ... ein gutes Beispiel für eine Aufzählung mit verschiedenen Tags für im Wesentlichen denselben logischen Wert.
Darrell Teague

5

Wie wäre es mit?

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 definiert mehrere nützliche Methoden, die für alle Aufzählungstypen in Java verfügbar sind:

  • Sie können die name()Methode verwenden, um den Namen aller Enum-Konstanten abzurufen. String-Literal zum Schreiben von Enum-Konstanten ist ihr Name.
  • In ähnlicher values()Weise kann die Methode verwendet werden, um ein Array aller Enum-Konstanten von einem Enum-Typ abzurufen.
  • Und für die gestellte Frage können Sie eine valueOf()Methode verwenden, um einen beliebigen String in eine Enum-Konstante in Java zu konvertieren, wie unten gezeigt.
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

In diesem valueOf()Codeausschnitt gibt die Methode eine Enum-Konstante Gender.MALE zurück, die den Namen aufruft, der zurückgegeben wird "MALE".


4

Die commons-lang- Bibliothek von Apache verfügt über eine statische Funktion org.apache.commons.lang3.EnumUtils.getEnum, die Ihrem Enum-Typ einen String zuordnet . Dieselbe Antwort im Wesentlichen wie bei Geoffreys, aber warum sollten Sie Ihre eigenen rollen, wenn es schon in freier Wildbahn ist?


1
Fairer Kommentar (DRY), aber ... während die meisten Apache Commons-Sachen großartig sind, habe ich selbst einige Fehler und Anti-Patterns in dieser Basis gefunden. Wenn man sich also auf Joshua Blochs Implementierung bezieht, könnte dies auf einem stärkeren Fundament stehen. Dann müssen Sie den Apache-Code überprüfen, um zu wissen, was jemand implementiert hat. Wenn es heißt, der berühmte Doug Leah, der die Java-Parallelität neu geschrieben hat ... dann würde ich ihm implizit vertrauen.
Darrell Teague

4

Hinzufügen zu der am besten bewerteten Antwort mit einem hilfreichen Dienstprogramm ...

valueOf() löst zwei verschiedene Ausnahmen aus, wenn die Eingabe nicht gefällt.

  • IllegalArgumentException
  • NullPointerExeption

Wenn Ihre Anforderungen so sind, dass Sie keine Garantie dafür haben, dass Ihr String definitiv mit einem Aufzählungswert übereinstimmt, z. B. wenn die String-Daten aus einer Datenbank stammen und eine alte Version der Aufzählung enthalten könnten, müssen Sie diese verarbeiten häufig...

Hier ist eine wiederverwendbare Methode, mit der wir eine Standard-Enum definieren können, die zurückgegeben werden soll, wenn der von uns übergebene String nicht übereinstimmt.

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

Verwenden Sie es so:

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

Da eine switch-Version noch nicht erwähnt wurde, stelle ich sie vor (Wiederverwendung der Aufzählung von 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);
      }
    }
  }

Da dies der valueOf(String name)Methode keinen zusätzlichen Wert verleiht , ist es nur dann sinnvoll, eine zusätzliche Methode zu definieren, wenn wir ein anderes Verhalten wünschen. Wenn wir keine erhöhen möchten, IllegalArgumentExceptionkönnen wir die Implementierung ändern in:

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

Durch die Angabe eines Standardwertes behalten wir den Vertrag bei, Enum.valueOf(String name)ohne einen IllegalArgumentException auf diese Weise zu werfen , der in keinem Fall nullzurückgegeben wird. Deshalb werfen wir ein NullPointerExceptionif der Name ist nullund falls defaultif defaultValueist null. So valueOfOrDefaultfunktioniert es.

Dieser Ansatz übernimmt das Design der Map-Interface, die eine Methode Map.getOrDefault(Object key, V defaultValue)ab Java 8 bereitstellt .


1

Ein weiteres Dienstprogramm, das in umgekehrter Weise erfasst. Verwenden eines Werts, der diese Aufzählung identifiziert, nicht anhand ihres Namens.

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

Beispiel:

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")Gibt zurück Foo.THREE, da es verwendet wird, getValueum mit "drei" übereinzustimmen, einer eindeutigen öffentlichen, nicht endgültigen und nicht statischen Methode in Foo. Wenn Foo beispielsweise mehr als eine öffentliche, keine endgültige und keine statische Methode hat, getTranslatedie "drei" zurückgibt, kann die andere Methode verwendet werden : EnumUtil.from(Foo.class, "drei", "getTranslate").


1

Kotlin-Lösung

Erstellen Sie eine Nebenstelle und rufen Sie dann an valueOf<MyEnum>("value"). Wenn der Typ ungültig ist, erhalten Sie null und müssen damit umgehen

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

Alternativ können Sie einen Standardwert festlegen, aufrufen valueOf<MyEnum>("value", MyEnum.FALLBACK)und eine Nullantwort vermeiden. Sie können Ihre spezifische Aufzählung so erweitern, dass die Standardeinstellung automatisch ist

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

Oder wenn Sie beides wollen, machen Sie das zweite:

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

Glaubst du, deine Antwort wird hier ein besseres Zuhause haben? stackoverflow.com/questions/28548015/…
nabster

0

Ich verwende diese Art von Prozess gerne, um Befehle als Zeichenfolgen in Aufzählungen zu analysieren. Normalerweise habe ich eine der Aufzählungen als "unbekannt", daher ist es hilfreich, diese zurückzugeben, wenn die anderen nicht gefunden werden (auch wenn die Groß- und Kleinschreibung nicht berücksichtigt wird) und nicht null (dh es gibt keinen Wert). Daher verwende ich diesen Ansatz.

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

Der schnellste Weg, um den Namen von enum zu erhalten, besteht darin, beim Start der Anwendung eine Karte mit Aufzählungstext und -wert zu erstellen. Um den Namen zu erhalten, rufen Sie die Funktion Blah.getEnumName () auf:

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());
    } 
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.