web-dev-qa-db-ja.com

Javaで文字列値から列挙値を取得する方法

私はちょうどある列挙型を持っているとしましょう

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

そして私は文字列のenum値を見つけたいと思います、例えば"A"Blah.Aになります。どうすればこれが可能でしょうか。

Enum.valueOf()は必要なメソッドですか?もしそうなら、私はこれをどのように使用しますか?

1794
Malachi

はい、Blah.valueOf("A")はあなたにBlah.Aを与えます。

大文字と小文字の区別も含めて、名前は exact に一致する必要があることに注意してください。Blah.valueOf("a")Blah.valueOf("A ")はどちらもIllegalArgumentExceptionをスローします。

静的メソッドvalueOf()values()はコンパイル時に作成され、ソースコードには現れません。ただし、それらはJavadocに表示されます。たとえば、 Dialog.ModalityType は両方の方法を示します。

2064
Michael Myers

テキストが列挙値と同じでない場合の別の解決策:

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

これは私が使う気の利いたユーティリティです。

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

それから私のenumクラスで、私は通常これを持っていていくつかのタイピングを節約します:

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

列挙型がすべて大文字ではない場合は、Enum.valueOf行を変更するだけです。

残念ながら、Tは消去されているので、T.classEnum.valueOfを使用することはできません。

110
Geoffrey Zheng

あなたはあなたのケースにも注意を払うべきです。 Blah.valueOf("A")はうまくいきますが、Blah.valueOf("a")はうまくいきません。それからBlah.valueOf("a".toUpperCase(Locale.ENGLISH))はうまくいきます。

編集
tc。commentJava docs に基づいてtoUpperCasetoUpperCase(Locale.ENGLISH)に変更

edit2 Androidでは sulaiが指摘 と同じように Locale.US を使うべきです。

72
João Portela

Joshua Blochのパターンを使用します。 Effective Java

(簡潔にするために簡略化)

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

また見なさい:

インスタンスのEnumおよびMapを使用したOracle Javaの例

Enum型の静的ブロックの実行順序

String値からJavaのenumを検索する方法

65
Darrell Teague

これはどのEnumに対してもできる方法で、大文字と小文字は区別されません。

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

Blah.valueOf(string)を使うのが最善ですが、Enum.valueOf(Blah.class, string)を使うこともできます。

31
Peter Lawrey

あなたがあなた自身のユーティリティを書きたくないのであれば、Googleの guava libraryを使ってください。

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

組み込みのJava関数とは異なり、AがBlahに存在し、例外をスローしないかどうかを確認しましょう。

26
Andrejs

私の2セントはここ:Java8 Streamsを使用して+正確な文字列をチェックすることです:

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

**編集**

この規則を使用して命名したので、関数の名前をfromString()に変更しました。Java言語自体からいくつかの利点が得られます。例えば:

  1. HeaderParamアノテーションで型を直接変換する
23
Manu

Java 8以降では、 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();
    }
}
20
Hans Schreuder

これが必要になるかもしれません:

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

もう一つの追加:

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

これにより、文字列化されたEnum名による値が返されます。 fromEnumNameに "PERSON"を指定すると、Enumの値、つまり "Person"が返されます。

14

Enumの暗黙の静的メソッドname()を使用することによるこれを行う別の方法。 nameは与えられた文字列と照合するために使用できるその列挙型を作成するために使用された正確な文字列を返します。

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

テスト:

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

//it will print B  B

インスピレーション: 10 JavaにおけるEnumの例

11
Vikram

Guavaライブラリを使用したソリューションメソッドgetPlanet()は大文字と小文字を区別しないので、getPlanet( "MerCUrY")は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();
   }
}
7
javabrew

これまでの答えに加えて、nullとNPEに関するいくつかの議論に対処するために、欠席/無効なケースを処理するためにGuava Optionalsを使用しています。これは、URI /パラメータの解析に最適です。

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

気付いていない人のために、Optionalでnullを回避する方法について、もう少し詳しく説明します: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional

6
tom

Java 8では、静的Mapパターンはさらに簡単で、私が好む方法です。もしあなたがJacksonでEnumを使いたいのであればtoStringをオーバーライドしてnameの代わりにそれを使うことができますそしてそれから@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);
    }
}
6
Novaterata
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.K

ハッシュマップを利用する古くから生成されたコードからヒントを得たO(1)メソッド。

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

}
4
Sisyphus

Apacheの commons-lang libraryには、静的な関数 org.Apache.commons.lang3.EnumUtils.getEnum があり、StringをEnum型にマッピングします。本質的にはGeoffreysと同じ答えですが、それがすでに野外に出ているときになぜ自分自身をロールバックするのか。

3
pjklauser

有用なユーティリティで、最高評価の答えに追加しています...

valueOf()は、入力が気に入らない場合に2つの異なる例外をスローします。

  • IllegalArgumentException
  • NullPointerExeption

あなたの要件があなたのStringが確実にenum値と一致するという保証がないというようなものであれば、例えばStringデータがデータベースから来て、古いバージョンのenumを含むことができるならば、あなたはこれらを扱う必要があります。しばしば...

それで、ここに私が書いた再利用可能なメソッドがあります。それは、渡された文字列が一致しない場合に返されるデフォルトのEnumを定義することを可能にします。

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

このように使用してください。

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

Java.lang.Enumは、Javaのすべての列挙型で利用可能ないくつかの便利なメソッドを定義しています。

  • Enum定数の名前を取得するためにname()メソッドを使うことができます。列挙型定数を書くのに使用される文字列リテラルはそれらの名前です。
  • 同様にvalues()メソッドを使用してEnum型からすべてのEnum定数の配列を取得することができます。
  • また、質問に対しては、valueOf()メソッドを使用して、以下に示すように、Javaで任意の文字列をEnum定数に変換できます。
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

このコードスニペットでは、valueOf()メソッドがEnum定数Gender.MALEを返し、nameを呼び出すと"MALE"が返されます。

3
KNU

Enumは非常に便利です。次の例のように、さまざまな言語のいくつかのフィールドの説明を追加するためにEnumをたくさん使用しています。

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

そして、getDescription(String lang)メソッドに渡された言語コードに基づいて動的に説明を取得できます。次に例を示します。

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

どうですか?

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

逆の方法でキャプチャするもう一つのユーティリティ。その名前からではなく、そのEnumを識別する値を使用します。

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

例:

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")Foo.THREEを返します、なぜならそれは "drei"にマッチするためにgetValueを使うからです。 Fooが一般公開以上の、finalやstaticメソッドではない、例えば "drei"を返すgetTranslateの場合、他のメソッドEnumUtil.from(Foo.class, "drei", "getTranslate")を使うことができます。

1
Moesio

__変数__-バージョンはまだ言及されていないので、私はそれを紹介します(OPのenumを再利用)。

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

これはvalueOf(String name)メソッドに追加の値を与えないので、異なる動作をさせたい場合にのみ追加のメソッドを定義することは意味があります。 switchを上げたくない場合は、実装を次のように変更できます。

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

デフォルト値を提供することで、IllegalArgumentExceptionをスローせずにIllegalArgumentExceptionを返さないようにすることで、Enum.valueOf(String name)contract を保持します。したがって、名前がnullの場合はNullPointerExceptionをスローし、nullの場合はdefaultdefaultValueの場合はnullをスローします。それがvalueOfOrDefaultのしくみです。

このアプローチは、Java 8以降でMap.getOrDefault(Object key, V defaultValue)メソッドを提供するMap- Interfaceの設計を採用しています。

1
LuCio

このようなプロセスを使用して、コマンドを文字列として列挙型に解析します。私は通常、列挙型の1つを "unknown"としているので、他のものが見つからない場合(大文字と小文字を区別しない場合でも)、null(つまり、値がないこと)を返すようにします。そこで私はこのアプローチを使います。

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

Enumの名前を取得する最も早い方法は、アプリケーションの起動時にenumのテキストと値のマップを作成し、その名前を取得するには関数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