Come ottenere un valore enum da un valore stringa in Java?


1984

Di 'che ho un enum che è giusto

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

e vorrei trovare il valore enum di una stringa, per esempio "A" quale sarebbe Blah.A. Come sarebbe possibile farlo?

È il Enum.valueOf()metodo di cui ho bisogno? Se è così, come dovrei usarlo?

Risposte:


2259

Sì, Blah.valueOf("A")ti darà Blah.A.

Nota che il nome deve corrispondere esattamente , incluso case: Blah.valueOf("a")ed Blah.valueOf("A ")entrambi lanciano unIllegalArgumentException .

I metodi statici valueOf()e values()vengono creati in fase di compilazione e non vengono visualizzati nel codice sorgente. Tuttavia, appaiono in Javadoc; ad esempio, Dialog.ModalityTypemostra entrambi i metodi.


100
Per riferimento, il Blah.valueOf("A")metodo fa distinzione tra maiuscole e minuscole e non tollera spazi bianchi estranei, quindi la soluzione alternativa proposta di seguito da @ JoséMi.
Brett,

3
@Michael Myers, Dal momento che questa risposta è di gran lunga la più votata, dovrei capire che è buona prassi definire un enum e il suo valore String in modo che siano esattamente gli stessi?
Kevin Meredith,

4
@KevinMeredith: Se intendi il toString()valore, no, non lo direi. name()ti darà il nome effettivo definito della costante enum a meno che tu non lo ignori.
Michael Myers

3
Cosa intendi esattamente con "sono creati in fase di compilazione e non compaiono nel codice sorgente". ?
treesAreEwherewhere

8
@treesAreEverywhere Più specificamente, questi metodi sono generati (o sintetizzati ) dal compilatore. La enum Blah {...}definizione effettiva non dovrebbe cercare di dichiarare valuesné propria valuesOf. È come scrivere "AnyTypeName.class" anche se in realtà non hai mai dichiarato una variabile membro "class"; il compilatore rende tutto Just Work. (Questa risposta potrebbe non esserti più utile 3 mesi dopo, ma per ogni evenienza.)
Ti Strga,

864

Un'altra soluzione se il testo non è uguale al valore di enumerazione:

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")sarebbe meglio di return null.
whiskeysierra,

8
@whiskeysierra Jon Skeet non sarebbe d'accordo. stackoverflow.com/questions/1167982/...
Sanghyun Lee

11
@Sangdol Potrebbe voi ci Enlight perché tornare nulla è meglio?
whiskeysierra,

57
@Sangdol di solito è una buona cosa controllare cosa sta facendo SUN - oops - Oracle nella stessa situazione. E come Enum.valueOf () sta mostrando, è la migliore pratica lanciare un'eccezione in questo caso. Perché è una situazione eccezionale. "Ottimizzazione delle prestazioni" è una cattiva scusa per scrivere codice illeggibile ;-)
raudi

5
Bene, potresti anche usare l'annotazione @Nullable per renderla "leggibile" ;-)
JoséMi

121

Ecco una bella utility che uso:

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

Quindi nella mia classe enum di solito ho questo per salvare un po 'di battitura:

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

Se le tue enumerazioni non sono tutte maiuscole, basta cambiare il Enum.valueOf linea.

Peccato che non posso usare T.classper Enum.valueOfcome Tè cancellato.


176
Quel blocco di cattura vuoto mi fa davvero impazzire, scusa.
whiskeysierra,

32
@LazloBonin: le eccezioni sono per condizioni eccezionali, non per il flusso di controllo. Procuratevi una copia di Effective Java .
Ripristina Monica - M. Schröder il

10
Se l'API Java che si desidera utilizzare genera un'eccezione e non si desidera che il codice ne generi una, è possibile ingoiare l'eccezione in questo modo o riscrivere la logica da zero, in modo che non venga generata alcuna eccezione. Ingoiare l'eccezione è spesso il male minore.
Nate CK,

47
Orribile! Sempre, sempre le eccezioni in cui puoi gestirle. L'esempio sopra è un esempio perfetto di come NON farlo . Perché? Quindi restituisce NULL e il chiamante deve quindi verificare NULL o lanciare un NPE. Se il chiamante sa come gestire la situazione, fare un if vs. try-catch può sembrare un po 'più elegante, MA se non riesce a gestire deve passare di nuovo null e il chiamante di nuovo deve verificare contro NULL , ecc. ecc.
raudi,

10
Per essere onesti con la soluzione sopra, ci sono davvero casi di utilizzo che richiedono di restituire null invece di lanciare IllegalArgumentException e interrompere il flusso del programma, ad esempio mappando gli enum tra uno schema di servizi Web e uno schema di database in cui non sono sempre uno -to-uno. Tuttavia, concordo sul fatto che il blocco di cattura non dovrebbe mai essere lasciato vuoto. Inserisci un codice come log.warn o qualcosa per scopi di monitoraggio.
Adrian M,

102

Usa lo schema di Joshua Bloch, Effective Java :

(semplificato per brevità)

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

Vedi anche:

Oracle Java Esempio usando Enum e Mappa delle istanze

Ordine di esecuzione di blocchi statici in un tipo Enum

Come posso cercare un enum Java dal suo valore String


4
se Joshua Bloch l'ha detto, allora questo è l'unico modo per andare :-). È un peccato che devo sempre scorrere qui.
Dermoritz,

11
Questo è ancora più semplice in Java 8 come puoi fare: Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))ti consiglio anche di sovrascrivere toString () (passato attraverso il costruttore) e di usarlo al posto del nome, specialmente se l'Enum è associato a dati serializzabili in quanto ti consente di controllare il case senza dare Sonar adatto.
Novaterata,

1
Java 8 sicuramente può / cambierà molte (migliori) risposte su questo forum. Non sono sicuro di avere mai la coda (Sonar) scuotere il cane (codice dell'applicazione) però.
Darrell Teague,

3
Se lo inserirai unmodifiableMapcomunque in, non c'è alcun vantaggio nell'iniziare con un ConcurrentHashMap. Basta usare a HashMap. (Se hai Guava, ImmutableMaplo consiglierei invece!)
Daniel Pryden l'

9
L'inizializzazione statica è intrinsecamente sincronizzata , quindi non c'è assolutamente motivo di usarla ConcurrentHashMapqui, dove la mappa non viene mai modificata dopo l'inizializzazione. Ecco perché anche ad esempio l'esempio nella stessa JLS usa un regolare HashMap.
Radiodef,

74

Dovresti anche stare attento con il tuo caso. Lasciami spiegare: fare Blah.valueOf("A")lavori, ma Blah.valueOf("a")non funzionerà. Poi di nuovoBlah.valueOf("a".toUpperCase(Locale.ENGLISH)) avrebbe funzionato.

modifica
Modificato in toUpperCasein toUpperCase(Locale.ENGLISH)base a tc. commento e documenti java

edit2 Su Android dovresti usare Locale.US, come sottolinea Sulai .


6
Diffidare delle impostazioni internazionali predefinite!
tc.

3
Per voi utenti Android, vorrei sottolineare che la documentazione di Android incoraggia esplicitamente l'uso di Locale.USinput / output leggibili dalla macchina.
Sulai,

2
@Trengot Sì, sfortunatamente. La Turchia è un buon esempio. Combinalo con la gestione interrotta di Java dei set di caratteri predefiniti (il valore predefinito è Latino su Windows anziché Unicode) e scoprirai che quasi sempre non è sicuro utilizzare le versioni predefinite dei metodi che accettano un set di caratteri o impostazioni internazionali. Dovresti quasi sempre definirli esplicitamente.
Stijn de Witt,

Non sono sicuro che i set di caratteri "predefiniti" di Java e altri siano "rotti" di per sé ma concessi, il default su UTF-8 al posto delle sostituzioni (che dovrebbe essere fatto sempre per essere esplicito) avrebbe reso sistemi migliori per i programmatori junior che comunemente non riescono a capire concetti di set di caratteri.
Darrell Teague,

38

Ecco un metodo che può farlo per qualsiasi Enum ed è case sensitive.

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

Questa variazione lo sta facendo correttamente: equalsIgnoreCaseè la strada da percorrere. +1
Stijn de Witt,

Come la distinzione tra maiuscole e minuscole, ma ... preferisce gli Enum rispetto alle assegnazioni di stringhe (casuali) per le chiavi e ... minori ma l'iterazione è meno performante per una ricerca così ripetitiva. Quindi impl di EnumMap et al.
Darrell Teague,

Questo non funziona ! Ho cambiato equalsIgnoreCase in uguale per il mio scopo. Il codice ha avuto esito negativo anche se entrambi gli input per uguali erano esattamente gli stessi.
MasterJoe2,

36

Usare Blah.valueOf(string)è il migliore ma puoi anche usarlo Enum.valueOf(Blah.class, string).


1
Case sensitive, non aiuta!
Murtaza Kanchwala,

@MurtazaKanchwala Puoi chiarire il tuo commento? Cosa stai cercando di fare?
Peter Lawrey,

2
Ciao @PeterLawrey, stavo cercando di recuperare un Enum da un enum pubblico String ObjectType {PERSON ("Person") public String parameterName; ObjectType (String parameterName) {this.parameterName = parameterName; } public String getParameterName () {return this.parameterName; } public ObjectType statico fromString (String parameterName) {if (parameterName! = null) {for (ObjectType objType: ObjectType.values ​​()) {if (parameterName.equalsIgnoreCase (objType.parameterName)) {return objType; }}} return null; }}
Murtaza Kanchwala,

35

In Java 8 o versioni successive, utilizzando 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();
    }
}

Non sono sicuro che questa sia in qualche modo una risposta migliore. I flussi in questo caso sono un iteratore a thread singolo come qualsiasi altro su tutti i valori e probabilmente meno performante di un impianto di ricerca di mappe. Gli stream hanno più valore in un contesto multi-thread in cui, ad esempio, l'esecuzione parallela di un file di testo separato da newline può migliorare le prestazioni.
Darrell Teague,

28

Se non vuoi scrivere la tua utility, usa Google biblioteca:

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

A differenza della funzione Java integrata, ti consente di verificare se A è presente in Blah e non genera un'eccezione.


7
parte triste è, questo restituisce un google opzionale e non java opzionale
javaProgrammer

Vero. Esaurito però. Google e Netflix hanno ottime librerie Java. In caso di sovrapposizione con le classi di recupero Java implementate nelle versioni più recenti, si verificano inevitabilmente problemi. Tipo di essere all in su un lib fornitore.
Darrell Teague,

26

I miei 2 centesimi qui: usando Java8 Streams + controllando una stringa esatta:

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

** MODIFICARE **

Rinominata la funzione da fromString()quando la ha denominata usando quella convenzione, otterrai alcuni vantaggi dal linguaggio Java stesso; per esempio:

  1. Conversione diretta dei tipi all'annotazione HeaderParam

1
In alternativa, per consentire la scrittura di switchblocchi più leggibili , è possibile .orElse(null)invece .orElseThrow()che sia possibile codificare il lancio dell'eccezione nella defaultclausola e includere ulteriori informazioni utili quando richiesto. E per renderlo più indulgente potresti usarev -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Adam,

o semplicemente restituire il Optionalda findFirst(), consentendo all'utente di decidere se vuole .orElse(null), orElseThrow()o altro ....
user85421

1
Dichiarare a public static MyEnum valueOf(String)è in realtà un errore di compilazione, poiché è uguale a quello implicitamente definito, quindi la versione precedente della tua risposta è effettivamente migliore. ( jls , ideone )
Radiodef,

Nella mia opzione è meglio evitare Eccezioni e usare Opzionale. Accanto a ciò dovremmo annullare null e utilizzare anche facoltativo.
Hans Schreuder,

Ancora una volta, ricorda che anche se il codice è meno o più bello ... un'implementazione di Stream come questa è solo un iteratore su tutti i valori rispetto a una ricerca della mappa (meno performante).
Darrell Teague,

16

Potrebbe essere necessario questo:

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

Un'altra aggiunta:

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

Questo ti restituirà il valore con un nome Enum rigoroso Ad esempio, se fornisci "PERSON" nel fromEnumName, ti restituirà il valore di Enum, ovvero "Person"


13

Un altro modo per farlo utilizzando il metodo statico implicito name()di Enum. name restituirà la stringa esatta utilizzata per creare quell'enum che può essere utilizzato per verificare la stringa fornita:

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:

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

//it will print B  B

ispirazione: 10 esempi di Enum in Java


7
Questo è essenzialmente ciò che valueOffa per te. Questo metodo statico non offre nulla in più, ad eccezione di tutti. Quindi i costrutti if / else sono altamente pericolosi ... qualsiasi nuova costante enum aggiunta causerà la rottura di questo metodo senza modifiche.
YoYo

Considera anche questo esempio di come possiamo usare valueOf per fare una ricerca senza distinzione tra maiuscole e minuscole, o di come possiamo evitare le sue eccezioni e utilizzare alias per fornire nomi alternativi: stackoverflow.com/a/12659023/744133
YoYo

2
name()non è statico.
nrubin29,

10

Soluzione che utilizza librerie Guava. Il metodo getPlanet () non fa distinzione tra maiuscole e minuscole, quindi getPlanet ("MerCUrY") restituirà 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();
   }
}

8

Per aggiungere alle risposte precedenti e affrontare alcune delle discussioni su null e NPE sto usando Guava Optionals per gestire casi assenti / non validi. Funziona benissimo per l'analisi URI / parametri.

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

Per coloro che non ne sono a conoscenza, ecco alcune informazioni su come evitare null con Opzionale: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional


Questa è davvero una buona risposta per i modelli correlati e l'uso di Opzionale all'interno di un Enum - sfruttando il fatto che anche gli Enum sono classi e quindi possono essere decorati con metodi, metodi di override, ecc. È un buon caso per la programmazione fluente anche dal momento che i null restituiti dai metodi rendono tale costrutto errato (NPE in luoghi sconosciuti nelle catene fluenti di chiamate di metodo).
Darrell Teague,

8

In Java 8 il modello di mappa statica è ancora più semplice ed è il mio metodo preferito. Se si desidera utilizzare l'Enum con Jackson, è possibile eseguire l'override di String e utilizzarlo al posto del nome, quindi annotare con@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 è un'implementazione JSON (JavaScript Object Notation). La domanda originale non aveva nulla a che fare con JSON.
Darrell Teague,

La parte JSON era solo roba bonus che ho trovato rilevante all'epoca, poiché ottenere un Enum da una stringa è fondamentalmente un tipo di deserializzazione e JSON / Jackson è probabilmente la soluzione di serializzazione più popolare.
Novaterata,

Capisci, ma dal punto di vista della moderazione: non ha contribuito a rispondere alla domanda del PO, quindi sto solo cercando di aiutare a impostare il contesto lì.JSON è davvero la strada da percorrere per convertire gli oggetti in forma canonica in Java con Jackson che è una grande biblioteca.
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;
}

dare un'occhiata a questo link per le guide a rispondere e porre domande sulla stackoverflow.com: stackoverflow.com/faq
bakoyaro

1
È più o meno la stessa della risposta di José Mi
Rup,

6

O (1) metodo ispirato al codice generato dall'usato che utilizza una 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;
        }

}

Notare che gli identificatori zero (0) e uno (1) non sono necessari. Il metodo Enum valor () restituirà i membri nello stesso ordine del codice. Quindi la prima voce sarà zero ordinale, la seconda, ecc.
Darrell Teague,

6

Enum è molto utile, ho usato Enummolto per aggiungere una descrizione per alcuni campi in diverse lingue, come nell'esempio seguente:

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

Quindi puoi recuperare la descrizione in modo dinamico in base al codice della lingua passato al getDescription(String lang)metodo, ad esempio:

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

1
Un buon esempio per spingere ulteriormente Enums. Avrebbe reso la codifica del linguaggio usando i nomi statici standard e la ricerca in una mappa ma comunque ... un buon esempio di avere un enum con tag diversi per quello che è essenzialmente lo stesso valore logico.
Darrell Teague,

5

Che dire?

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 definisce diversi metodi utili, disponibili per tutti i tipi di enumerazione in Java:

  • È possibile utilizzare il name()metodo per ottenere il nome di qualsiasi costante Enum. Il letterale stringa usato per scrivere costanti di enum è il loro nome.
  • Allo stesso modo il values()metodo può essere usato per ottenere una matrice di tutte le costanti Enum da un tipo Enum.
  • E per la domanda posta, puoi usare il valueOf()metodo per convertire qualsiasi stringa in costante Enum in Java, come mostrato di seguito.
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 questo frammento di codice, il valueOf()metodo restituisce una costante Enum Gender.MALE, chiamando il nome su quel ritorno "MALE".


4

La libreria commons-lang di Apache ha una funzione statica org.apache.commons.lang3.EnumUtils.getEnum che mapperà una stringa sul tuo tipo Enum. Stessa risposta essenzialmente di Geoffreys, ma perché farlo da solo quando è già in circolazione.


1
Commento discreto (DRY) ma ... mentre la maggior parte delle cose di Apache Commons è fantastica, ho trovato diversi bug e anti-pattern in quella base. Pertanto, riferendosi a dire che l'implementazione di Joshua Bloch potrebbe essere più solida. Riesce quindi a rivedere il codice Apache per sapere cosa qualcuno ha implementato. Se fosse stato il famoso Doug Leah a riscrivere la concorrenza di Java ... allora mi sarei fidato implicitamente.
Darrell Teague,

4

Aggiungendo alla risposta più votata, con un'utilità utile ...

valueOf() genera due diverse eccezioni nei casi in cui non gli piace il suo input.

  • IllegalArgumentException
  • NullPointerExeption

Se i tuoi requisiti sono tali da non avere alcuna garanzia che la tua stringa corrisponderà sicuramente a un valore enum, ad esempio se i dati String provengono da un database e potrebbero contenere una versione precedente dell'enum, allora dovrai gestirli spesso...

Quindi ecco un metodo riutilizzabile che ho scritto che ci consente di definire un Enum predefinito da restituire se la stringa che passiamo non corrisponde.

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

Usalo in questo modo:

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

Dato che una switchversione non è stata ancora menzionata, la presento (riutilizzando l'enum del PO):

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

Dal momento che questo non dà alcun valore aggiuntivo al valueOf(String name)metodo, ha senso definire un metodo aggiuntivo solo se vogliamo avere un comportamento diverso. Se non vogliamo sollevare un IllegalArgumentException, possiamo cambiare l'implementazione 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;
      }
    }
  }

Fornendo un valore predefinito manteniamo il contratto di Enum.valueOf(String name)senza gettare un IllegalArgumentException in quel modo che in nessun caso nullviene restituita. Pertanto lanciamo a NullPointerExceptionse il nome è nulle in caso di defaultse lo defaultValueè null. valueOfOrDefaultFunziona così .

Questo approccio adotta il design di Map-Interface che fornisce un metodo a Map.getOrDefault(Object key, V defaultValue)partire da Java 8.


1

Un'altra utilità catturare in modo inverso. Utilizzando un valore che identifica quell'Enum, non dal suo nome.

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

Esempio:

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")ritorna Foo.THREE, perché utilizzerà getValueper abbinare "drei", che è un metodo pubblico unico, non definitivo e non statico in Foo. Nel caso Foo ha più il metodo pubblico, non definitivo e non statica, ad esempio, getTranslateche restituisce "drei", l'altro metodo può essere utilizzato: EnumUtil.from(Foo.class, "drei", "getTranslate").


1

Soluzione di Kotlin

Creare un interno e quindi chiamare valueOf<MyEnum>("value"). Se il tipo non è valido, otterrai null e dovrai gestirlo

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

In alternativa, è possibile impostare un valore predefinito, chiamando valueOf<MyEnum>("value", MyEnum.FALLBACK)ed evitando una risposta nulla. Puoi estendere il tuo enum specifico per rendere automatico il default

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

O se vuoi entrambi, fai il secondo:

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

Pensi che la tua risposta avrà una casa migliore qui? stackoverflow.com/questions/28548015/...
nabster

0

Mi piace usare questo tipo di processo per analizzare i comandi come stringhe in enumerazioni. Normalmente ho una delle enumerazioni come "sconosciuta", quindi aiuta a far sì che venga restituita quando le altre non vengono trovate (anche su una base insensibile al maiuscolo / minuscolo) piuttosto che nulla (questo significa che non ha valore). Quindi uso questo approccio.

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

Il modo più rapido per ottenere il nome di enum è creare una mappa del testo e del valore di enum all'avvio dell'applicazione e ottenere il nome chiamando la funzione 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());
    } 
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.