enums esempio - Come ottenere un valore enum da un valore stringa in Java?




classe values (21)

Dì che ho un enum che è giusto

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

e mi piacerebbe trovare il valore enum di una stringa, ad esempio "A" che sarebbe Blah.A Come sarebbe possibile farlo?

Enum.valueOf() il metodo di cui ho bisogno? Se sì, come dovrei usare questo?


Answers

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 Enumerativo Strutturato. Ad esempio, se fornisci "PERSONA" in fromEnumName, ti restituirà il Valore di Enum, ovvero "Persona"


Dovresti anche stare attento al tuo caso. Lasciatemi spiegare: Blah.valueOf("A") funziona, ma Blah.valueOf("a") non funzionerà. Quindi ancora Blah.valueOf("a".toUpperCase(Locale.ENGLISH)) funzionerebbe.

modificare
Modificato toUpperCase to toUpperCase(Locale.ENGLISH) basato su tc. commento e i documenti java

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


Usare Blah.valueOf(string) è la cosa migliore ma puoi usare anche Enum.valueOf(Blah.class, string) .


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

Si noti che il nome deve essere una corrispondenza esatta , incluso il caso: Blah.valueOf("a") e Blah.valueOf("A ") generano entrambi IllegalArgumentException .

I metodi statici valueOf() e values() vengono creati in fase di compilazione e non appaiono nel codice sorgente. Appaiono in Javadoc, però; ad esempio, Dialog.ModalityType mostra entrambi i metodi.


Ecco un metodo che può farlo per qualsiasi Enum ed è insensibile al maiuscolo / minuscolo.

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

Un'altra utility che cattura in modo inverso. Usando un valore che identifica 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") restituisce Foo.THREE , perché utilizzerà getValue per far corrispondere "drei", che è un metodo pubblico, non definitivo e non statico in Foo. Nel caso in cui Foo abbia più di un metodo pubblico, non finale e non statico, ad esempio getTranslate che restituisce "drei", è possibile utilizzare l'altro metodo: EnumUtil.from(Foo.class, "drei", "getTranslate") .


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

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

java.lang.Enum definisce diversi metodi utili, disponibili per tutti i tipi di enumerazione in Java:

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


Mi piace usare questo tipo di processo per analizzare i comandi come stringhe nelle enumerazioni. Di solito ho una delle enumerazioni come "sconosciuta", quindi aiuta ad avere quella restituita quando gli altri non vengono trovati (anche su una base insensibile alle maiuscole e minuscole) piuttosto che null (che significa che non c'è alcun valore). Quindi io 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;
}

In Java 8 o Streams successive, utilizzando gli 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 Blah fromText(String text) {
        return Arrays.stream(values())
          .filter(bl -> bl.text.equalsIgnoreCase(text))
          .findFirst()
          .orElse(null);
    }
}


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

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

valueOf() genera due Eccezioni diverse nei casi in cui non gradisce il suo input.

  • IllegalArgumentException
  • NullPointerExeption

Se i tuoi requisiti sono tali da non avere alcuna garanzia che la tua stringa soddisfi sicuramente un valore enum, ad esempio se i dati String provengono da un database e potrebbero contenere una vecchia versione dell'enumerazione, 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
}

Metodo O (1) ispirato al codice generato da una deriva 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;
        }

}

Un altro modo per farlo usando il metodo statico implicito name() di Enum. il nome restituirà la stringa esatta utilizzata per creare quell'enumerazione che può essere utilizzata 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


Se non vuoi scrivere la tua utility usa la libreria guava di Google:

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

A differenza della funzione java integrata, è possibile controllare se A è presente in Blah e non lancia un'eccezione.


Come switch -version non è stato ancora menzionato, lo presento (riusando l'enum di 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);
      }
    }
  }

Poiché questo non fornisce alcun valore aggiuntivo al valueOf(String name) , ha senso solo definire un metodo addizionale 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 contract di Enum.valueOf(String name) senza lanciare un IllegalArgumentException in quel modo che in nessun caso viene restituito null . Pertanto gettiamo una NullPointerException se il nome è null e in caso di default se defaultValue è null . Ecco come funziona valueOfOrDefault .

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


Ecco un'utile utility che utilizzo:

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

Poi nella mia classe enum di solito ho questo per risparmiare un po 'di digitazione:

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

Se le tue enumerazioni non sono tutte maiuscole, modifica semplicemente la riga Enum.valueOf .

Peccato che non possa usare T.class per Enum.valueOf quando T viene cancellato.


Usa il modello 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 Example usando Enum e Map delle istanze

Ordine di esecuzione di blocchi statici in un tipo Enum

Come posso cercare un enum Java dal suo valore di stringa


Voglio completare la risposta dei poligenelubrificanti:

Personalmente preferisco gli uguali (). Ma fa il controllo di compatibilità di tipo. Quale penso sia una limitazione importante.

Per verificare la compatibilità dei tipi al momento della compilazione, dichiarare e utilizzare una funzione personalizzata nell'enumerazione.

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

Con questo, hai ottenuto tutti i vantaggi di entrambe le soluzioni: protezione NPE, codice di facile lettura e verifica della compatibilità del tipo in fase di compilazione.

Raccomando anche di aggiungere un valore UNDEFINED per enum.





java enums