web-dev-qa-db-fra.com

Comment obtenir une valeur enum à partir d'une valeur de chaîne en Java?

Dis que j'ai un enum qui est juste

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

et j'aimerais trouver la valeur enum d'une chaîne, par exemple "A" qui serait Blah.A. Comment serait-il possible de faire cela?

Est-ce que Enum.valueOf() est la méthode dont j'ai besoin? Si oui, comment pourrais-je l'utiliser?

1848
Malachi

Oui, Blah.valueOf("A") vous donnera _Blah.A_.

Notez que le nom doit être une correspondance exacte , y compris la casse: Blah.valueOf("a") et Blah.valueOf("A ") jettent tous deux une IllegalArgumentException .

Les méthodes statiques valueOf() et values() sont créées à la compilation et n'apparaissent pas dans le code source. Ils apparaissent dans Javadoc, cependant; Par exemple, Dialog.ModalityType affiche les deux méthodes.

2123
Michael Myers

Une autre solution si le texte n’est pas identique à la valeur d’énumération:

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;
    }
}
811
JoséMi

Voici un utilitaire astucieux que j'utilise:

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

Ensuite, dans mon cours d’énumération, j’ai l'habitude de garder ceci en mémoire:

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

Si vos enums ne sont pas tous en majuscules, changez simplement la ligne Enum.valueOf.

Dommage que je ne puisse pas utiliser T.class pour Enum.valueOf, car T est effacé.

116
Geoffrey Zheng

Utilisez le modèle de Joshua Bloch, Effective Java :

(simplifié pour la brièveté)

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

Regarde aussi:

Oracle Java Exemple utilisant Enum et Map of instances

Ordre d'exécution des blocs statiques dans un type Enum

Comment puis-je rechercher un Java enum à partir de sa valeur String

77
Darrell Teague

Vous devriez également faire attention à votre cas. Laissez-moi vous expliquer: faire Blah.valueOf("A") fonctionne, mais Blah.valueOf("a") ne fonctionnera pas. Là encore, Blah.valueOf("a".toUpperCase(Locale.ENGLISH)) fonctionnerait.

modifier
Remplacé toUpperCase par toUpperCase(Locale.ENGLISH) sur la base de tc. Comment et de la documentation Java

edit2 Sur Android, vous devez utiliser Locale.US , comme points sulai out .

73
João Portela

Voici une méthode qui peut le faire pour tout Enum, sans distinction de casse.

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

Utiliser Blah.valueOf(string) est préférable, mais vous pouvez également utiliser Enum.valueOf(Blah.class, string).

33
Peter Lawrey

Si vous ne voulez pas écrire votre propre utilitaire, utilisez la bibliothèque guava de Google:

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

Contrairement à la fonction Java intégrée, elle vous permet de vérifier si A est présent dans Blah et ne lève pas d'exception.

27
Andrejs

Dans Java 8 ou version ultérieure, à l'aide de 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();
    }
}
25
Hans Schreuder

Mes 2 centimes ici: utilisation de Java8 Streams + vérification d'une chaîne exacte:

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

** MODIFIER **

Vous avez renommé la fonction fromString() puisque vous l'avez nommée à l'aide de cette convention, vous tirerez parti du langage Java. par exemple:

  1. Conversion directe des types dans l'annotation HeaderParam
23
Manu

Vous devrez peut-être ceci:

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 ajout de plus:

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

Cela vous retournera la valeur par un nom d'énumération Stringified, par exemple. si vous fournissez "PERSON" dans le nom fromEnumName, la valeur Enum vous sera renvoyée, c'est-à-dire "Personne".

15
Murtaza Kanchwala

Une autre méthode consiste à utiliser la méthode statique implicite name() de Enum. name retournera la chaîne exacte utilisée pour créer cette énumération, qui peut être utilisée pour vérifier la chaîne fournie:

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

Essai:

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

//it will print B  B

inspiration: 10 exemples de Enum en Java

11
Vikram

Solution utilisant des bibliothèques Guava. La méthode getPlanet () n'étant pas sensible à la casse, getPlanet ("MerCUrY") renverra 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
javabrew

Dans Java 8, le modèle de carte statique est encore plus simple et constitue ma méthode préférée. Si vous souhaitez utiliser Enum avec Jackson, vous pouvez remplacer toString et l'utiliser à la place de name, puis annotez avec @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);
    }
}
7
Novaterata

Pour compléter les réponses précédentes et aborder certaines des discussions autour des valeurs nulles et NPE, j'utilise Guava Optionals pour traiter les cas absents/invalides. Cela fonctionne très bien pour l'analyse URI/paramètres.

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

Pour ceux qui ne sont pas au courant, voici quelques informations supplémentaires sur la façon d'éviter la valeur null avec Optional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional

6
tom

Méthode O (1) inspirée du code généré économiquement qui utilise un 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;
        }

}
5
Sisyphus
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;
}
5
Prasobh.Kollattu

La bibliothèque d'Apache commons-lang a une fonction statique org.Apache.commons.lang3.EnumUtils.getEnum qui mappera une chaîne sur votre type Enum. Même réponse essentiellement que Geoffreys mais pourquoi rouler le vôtre alors qu'il est déjà dans la nature.

4
pjklauser

Ajoutant à la réponse la mieux notée, avec un utilitaire utile ...

valueOf() lève deux exceptions différentes dans les cas où il n'aime pas son entrée.

  • IllegalArgumentException
  • NullPointerExeption

Si vos exigences ne vous garantissent pas que votre chaîne correspondra définitivement à une valeur d'énumération, par exemple si les données de chaîne proviennent d'une base de données et peuvent contenir une ancienne version de l'énum, ​​vous devrez alors les gérer. souvent...

Voici donc une méthode réutilisable que j'ai écrite et qui nous permet de définir un Enum par défaut à renvoyer si la chaîne que nous passons ne correspond pas.

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

Utilisez-le comme ceci:

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
}
4
lance.dolan

Java.lang.Enum définit plusieurs méthodes utiles, disponibles pour tous les types d'énumération en Java:

  • Vous pouvez utiliser la méthode name() pour obtenir le nom de toutes les constantes Enum. Le littéral de chaîne utilisé pour écrire les constantes enum est leur nom.
  • De même, la méthode values() peut être utilisée pour obtenir un tableau de toutes les constantes Enum à partir d'un type Enum.
  • Et pour la question posée, vous pouvez utiliser la méthode valueOf() pour convertir toute constante Chaîne en constante Enum en Java, comme indiqué ci-dessous.
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

Dans cet extrait de code, la méthode valueOf() renvoie une constante Enum, type Gender.MALE, qui appelle le nom qui renvoie "MALE".

3
KNU

Qu'en est-il de?

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

Enum est très utile, j'ai beaucoup utilisé Enum pour ajouter une description de certains champs dans différentes langues, comme dans l'exemple suivant:

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

Vous pouvez ensuite récupérer la description de manière dynamique en fonction du code de langue transmis à la méthode getDescription(String lang), par exemple:

String statusDescription = Status.valueOf("ACT").getDescription("en");
2
Ebraheem Alrabee'

Comme une version switch- n'a pas encore été mentionnée, je la présente (en réutilisant l'énumération de 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);
      }
    }
  }

Comme cela ne donne aucune valeur supplémentaire à la méthode valueOf(String name), il est logique de définir une méthode supplémentaire si nous voulons avoir un comportement différent. Si nous ne voulons pas élever une IllegalArgumentException, nous pouvons changer l'implémentation en:

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

En fournissant une valeur par défaut, nous conservons le contrat de Enum.valueOf(String name) sans lancer de IllegalArgumentException de cette manière. En aucun cas, null ne sera renvoyé. Nous lançons donc un NullPointerException si le nom est null et dans le cas de default si defaultValue est null. C'est ainsi que valueOfOrDefault fonctionne.

Cette approche adopte la conception de l'interface Map- qui fournit une méthode Map.getOrDefault(Object key, V defaultValue) à partir de Java 8.

2
LuCio

Un autre utilitaire capture en sens inverse. Utiliser une valeur qui identifie cet Enum, pas à partir de son nom.

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

Exemple:

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") renvoie Foo.THREE, car il utilisera getValue pour correspondre à "drei", méthode unique publique, non finale et non statique dans Foo. Dans le cas où Foo a plus d'une méthode publique, non finale et non statique, par exemple, getTranslate qui renvoie "drei", l'autre méthode peut être utilisée: EnumUtil.from(Foo.class, "drei", "getTranslate").

1
Moesio

J'aime utiliser ce type de processus pour analyser les commandes sous forme de chaînes dans des énumérations. Normalement, l’une des énumérations est "inconnue", il est donc utile de la renvoyer lorsque les autres ne sont pas trouvées (même sur une base insensible à la casse) plutôt que null (ce qui signifie qu’il n’ya pas de valeur). Par conséquent, j'utilise cette approche.

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;
}
0
John Hemming

Le moyen le plus rapide d’obtenir le nom d’énum est de créer une mappe de texte et de valeur enum au démarrage de l’application et d’obtenir le nom, appelez la fonction 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.toString());
        }
    }
    public static String getEnumName(String text) {
        return map.get(text.toLowerCase());
    } 
}
0
Bishal Jaiswal