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

StackOverflow https://stackoverflow.com/questions/604424

  •  03-07-2019
  •  | 
  •  

Question

Disons 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?

Était-ce utile?

La solution

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 ") lève tous les deux une IllegalArgumentException .

Les méthodes statiques valueOf () et valeurs () 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.

Autres conseils

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

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, ??j'ai généralement ceci pour enregistrer des dactylographies:

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

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

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

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

modifier
toUpperCase remplacé par toUpperCase (Locale.ENGLISH) en fonction de tc. comment et java docs

modifier2 Sur Android, vous devez utiliser Locale.US , comme sulai fait remarquer .

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

(simplifié pour des raisons de concision)

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

Voir aussi:

Exemple Oracle Java utilisant Enum et Map of instances

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

Comment puis-je rechercher un enum en Java à partir de sa valeur de chaîne

Voici une méthode qui peut le faire pour tout Enum et qui respecte la 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()
    ));
}

L'utilisation de Blah.valueOf (chaîne) est préférable, mais vous pouvez également utiliser Enum.valueOf (Blah.class, chaîne) .

Si vous ne voulez pas écrire votre propre utilitaire, utilisez le :

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

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

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

** EDIT **

Vous avez renommé la fonction en fromString () puisque vous l'avez nommée à l'aide de cette convention, vous tirerez des avantages du langage Java lui-même. par exemple:

  1. Conversion directe de types dans l'annotation HeaderParam

Sous Java 8 ou version ultérieure, utilisez 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();
    }
}

Vous aurez peut-être besoin de 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 supplémentaire:

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

Ceci vous retournera la valeur par un nom d'énumération sous forme de chaîne, par exemple si vous fournissez " PERSON " fromEnumName, il vous renverra la valeur de Enum, à savoir "Personne"

Une autre manière de procéder 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");
    }
}

Test:

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

//it will print B  B

inspiration: 10 exemples d'énum dans Java

Solution utilisant des bibliothèques Guava. La méthode getPlanet () est insensible à la casse, donc getPlanet ("MerCUrY") retournera 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();
   }
}

Pour ajouter des réponses aux 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 / non valides. 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 le savent pas, 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

Sous 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 par celui-ci au lieu de nom, 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);
    }
}
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;
}

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

}

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, le nom de l'appelant qui renvoie "MALE" / .

La bibliothèque de commons-lang d’Apache 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.

Ajout à 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 sont telles que vous n'avez aucune garantie que votre chaîne correspondra définitivement à une valeur enum, 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, ??il vous faudra pour 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 à retourner 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
}

Qu'en est-il?

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 autre utilitaire capturant en sens inverse. Utiliser une valeur qui identifie cet Enum, pas par 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 ", qui est une méthode publique unique, pas finale ni 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") .

En tant que switch , la version n'a pas encore été mentionnée, je l'introduis (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);
      }
    }
  }

Etant donné que 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 générer une IllegalArgumentException , nous pouvons modifier 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 (nom de chaîne) sans générer une IllegalArgumentException de cette manière que aucun cas null n'est renvoyé. Par conséquent, nous lançons une 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.

J'aime utiliser ce type de processus pour analyser les commandes sous forme de chaînes en énumérations. Normalement, l’une des énumérations est "inconnue". il est donc utile d’avoir ce résultat lorsque les autres ne sont pas trouvés (même sur une base insensible à la casse) plutôt que null (ce qui signifie qu’il n’ya pas de valeur). C’est pourquoi 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;
}

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, puis d’appeler 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());
    } 
}

Enum est très utile. J'utilise beaucoup 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;
    }
}

Ensuite, vous pouvez 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");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top