Javaで文字列値から列挙値を取得するにはどうすればよいですか?


1984

ちょうど列挙型があるとしましょう

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

そして私は、たとえば、文字列の列挙型の値を見つけたい"A"だろうBlah.A。これを行うにはどうすればよいでしょうか?

であるEnum.valueOf()私が必要方法?もしそうなら、私はこれをどのように使用しますか?

回答:


2258

はい、Blah.valueOf("A")与えますBlah.A

名前がなければならないことに注意正確な:ケースを含め、試合Blah.valueOf("a")Blah.valueOf("A ")両方投げますIllegalArgumentException

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


100
参考までに、このBlah.valueOf("A")メソッドは大文字と小文字を区別し、無関係な空白を許容しないため、@JoséMiが以下で提案する代替ソリューションを使用します。
ブレット

3
@Michael Myers、この回答は最も多く投票されているので、列挙型とその文字列値をまったく同じになるように定義することは良い習慣であることを理解する必要がありますか?
ケビンメレディス14

4
@KevinMeredith:toString()値を意味するなら、いいえ、私はそれを言っていません。name()オーバーライドしない限り、列挙定数の実際に定義された名前を取得します。
マイケル・マイヤーズ

3
「コンパイル時に作成され、ソースコードに表示されない」とはどういう意味ですか。?
treesAreEverywhere 2014年

8
@treesAreEverywhereより具体的には、これらのメソッドはコンパイラーによって生成(または合成)されます。実際のenum Blah {...}定義は、それ自体をvaluesも宣言しようとするべきではありませんvaluesOf。「クラス」メンバー変数を実際に宣言したことがなくても、「AnyTypeName.class」を書き込む方法に似ています。コンパイラーはすべてを正しく動作させます。(この回答は、3か月後には役に立たなくなる可能性がありますが、
念のため

864

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

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")より良いでしょうreturn null
ウィスキー

8
@whiskeysierra Jon Skeetはそれに同意しません。stackoverflow.com/questions/1167982/...
Sanghyunリー

11
@Sangdolはでしたあなた nullを返す方が良い理由教えてください。
ウイスキーシエラ'09

57
@Sangdol通常、SUNを確認することは良いことです-おっと-Oracleが同じ状況で実行しています。そしてようEnum.valueOf()は、表示されているIS、この場合に例外をスローすることをお勧め。なぜなら、それは例外的な状況です。「パフォーマンスの最適化」は、読み取り不可能なコードを書くための悪い言い訳です;-)
raudi

5
さて、あなたはまた、;-)、それが「読める」にするために@Nullable注釈を利用することができ
ホセミ

121

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

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

次に、私の列挙型クラスでは、通常、入力を節約するためにこれを使用します。

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

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

あまりにも悪い私が使用できないT.classためEnum.valueOfとして、T消去されます。


176
その空のキャッチブロックは本当にすみません、すみません。
ウイスキー

32
@LazloBonin:例外は例外的な条件であり、制御フローではありません。効果的なJavaのコピーを入手してください。
モニカの復活-M.シュレーダー

10
使用するJava APIが例外をスローし、コードが例外をスローしないようにする場合は、このように例外を飲み込むか、最初から例外をスローしないようにロジックをゼロから書き直すことができます。例外を飲み込むことは、多くの場合、それほど悪ではありません。
Nate CK、

47
恐ろしい!常に、例外を処理できる場所で常にキャッチします。上記の例は、それを行わない方法の完璧な例です。どうして?そのため、NULLを返し、呼び出し元はNULLをチェックするか、NPEをスローする必要があります。呼び出し側が状況を処理する方法を知っているなら、やって対ののtry-catchは、もう少しエレガントに見えることがあり、場合しかし、彼が扱うことができないならば、彼は再びヌルを通過しなければならないと、呼び出し元の呼び出し側が再び NULLに対してチェックする必要があります、などなど
raudi

10
上記のソリューションを公平にするために、実際にはIllegalArgumentExceptionをスローする代わりにnullを返し、プログラムのフローを中断する必要がある場合があります。たとえば、列挙型を常に1つではないWebサービススキーマとデータベーススキーマの間で列挙型をマッピングします。一対一。ただし、catchブロックを空のままにしないでください。追跡の目的で、log.warnなどのコードを配置します。
エイドリアンM

101

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を検索するにはどうすればよいですか


4
Joshua Blochがそれを言った場合、これが唯一の方法です:-)。いつもここまでスクロールしなければならないのは残念です。
dermoritz 2017年

11
これはあなたができるようにJava 8ではさらに簡単です:Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))特にEnumがシリアル化可能なデータに関連付けられている場合、これを使用せずに大文字と小文字を制御できるため、toString()(コンストラクタを通じて渡される)をオーバーライドし、名前の代わりに使用することをお勧めしますソナーフィット。
Novaterata 2017

1
Java 8は確かにこのフォーラムの多くの(より良い)回答を変更する可能性があります。しっぽ(ソナー)が犬(アプリケーションコード)を振るのかどうかはわかりません。
ダレルティーグ

3
unmodifiableMapとにかくそれを置くつもりなら、それから始めることには何の利益もありませんConcurrentHashMap。だけを使用してくださいHashMap。(もしあなたがグアバを持っているならImmutableMap、私は代わりにそれをお勧めします!)
ダニエル・プライデン

9
静的な初期化は本質的に同期されるため、ConcurrentHashMapここで使用する理由はまったくありません。初期化後にマップが変更されることはありません。したがって、なぜJLS自体の例でも通常のを使用するのでしょうかHashMap
Radiodef

74

ケースにも注意が必要です。説明させてください:うまくBlah.valueOf("A")いくが、Blah.valueOf("a")うまくいきません。またBlah.valueOf("a".toUpperCase(Locale.ENGLISH))動作します。

編集tcに基づいてに
変更toUpperCasetoUpperCase(Locale.ENGLISH)れました。コメントJavaドキュメント

edit2 sulaiが指摘する ようにLocale.US、Android では使用する必要があります。


6
デフォルトのロケールに注意してください!
tc。

3
Androidユーザーの皆さんのために、AndroidのドキュメントLocale.USで機械可読入出力の使用を明示的に推奨していることを指摘しておきます。
sulai 2013

2
@Trengotはい、残念ながら。トルコは良い例です。これをJavaのデフォルトの文字セットの処理(デフォルトではUnicodeではなくラテン語)と組み合わせると、文字セットまたはロケールを受け入れるメソッドのデフォルトバージョンを使用することがほとんど常に安全でないことがわかります。ほとんどの場合、明示的に定義する必要があります。
Stijn de Witt

Javaの「デフォルト」の文字セット自体が「壊れている」かどうかは確かですが、オーバーライドの代わりにUTF-8にデフォルト設定すること(これは常に明示的に行う必要があります)は、一般に理解できないジュニアプログラマにとってより良いシステムになります。文字セットの概念。
ダレルティーグ

38

これは、任意の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()
    ));
}

このバリエーションはそれを正しく行っています:equalsIgnoreCase方法です。+1
Stijn de Witt

大文字と小文字を区別しないのと同じですが、...キーには(ランダムな)文字列割り当てよりもEnumを優先します。したがって、EnumMapらの実装。
ダレルティーグ

これは動作しません !目的のために、equalsIgnoreCaseをequalsに変更しました。equalsへの両方の入力がまったく同じであっても、コードは失敗しました。
MasterJoe2

36

使用するのBlah.valueOf(string)が最適ですが、使用することもできますEnum.valueOf(Blah.class, string)


1
大文字と小文字が区別され、役に立ちません!
Murtaza Kanchwala

@MurtazaKanchwalaコメントを明確にできますか?あなたは何をしようとしているのですか?
Peter Lawrey、2015年

2
こんにちは@PeterLawreyです。文字列から列挙型を取得しようとしましたpublic enum ObjectType {PERSON( "Person")public String parameterName; ObjectType(String parameterName){this.parameterName = parameterName; } public String getParameterName(){return this.parameterName; } public static ObjectType fromString(String parameterName){if(parameterName!= null){for(ObjectType objType:ObjectType.values()){if(parameterName.equalsIgnoreCase(objType.parameterName)){return objType; }}} nullを返します。}}
Murtaza Kanchwala

34

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

これがどういうわけか、より良い答えであるかどうかはわかりません。この場合のストリームは、他のすべての値と同様にシングルスレッドのイテレータであり、マップルックアップの実装よりもおそらくパフォーマンスが劣ります。ストリームは、たとえば、改行で区切られたテキストファイルの並列実行によってパフォーマンスを向上させることができるマルチスレッドコンテキストでより多くの価値があります。
ダレルティーグ

28

独自のユーティリティを作成したくない場合は、Googleの 図書館:

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

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


7
悲しい部分は、これはgoogleのオプションではなく、javaのオプションを返す
javaProgrammer

本当です。恐ろしいです。GoogleとNetflixには素晴らしいJavaライブラリがあります。新しいバージョンで実装されたJavaキャッチアップクラスとの重複がある場合、必然的に問題が発生します。一種のベンダーのlibにすべて含まれている必要があります。
ダレルティーグ

26

ここで私の2セント:Java8ストリームの使用+正確な文字列のチェック:

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アノテーションでの型の直接変換

1
または、より読みやすいswitchブロックを記述できるようにする.orElse(null)代わり.orElseThrow()に、default句に例外スローをコーディングして、必要に応じてより役立つ情報を含めることができます。そして、それをより寛大に使うためにv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Adam

あるいは単に返すOptionalからfindFirst()、彼が望んでいる場合は、ユーザーが決定できるように、.orElse(null)orElseThrow()または何...
user85421

1
aの宣言は、public static MyEnum valueOf(String)暗黙的に定義されたものと同じであるため、実際にはコンパイルエラーです。したがって、古いバージョンの回答の方が実際には優れています。(jlsideone
Radiodef 2018

私のオプションでは、例外を避け、オプションを使用することをお勧めします。次に、nullを無効にし、代わりにOptionalを使用する必要があります。
Hans Schreuder、

繰り返しになりますが、見栄えのよいコードが少なくてもよくても...このようなStream実装は、すべての値に対する反復子であり、マップルックアップ(パフォーマンスが低い)です。
ダレルティーグ

16

これが必要になる場合があります:

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

もう1つ追加:

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

これは、文字列化された列挙名によって値を返します。たとえば、fromEnumNameに「PERSON」を指定すると、列挙型の値、つまり「Person」が返されます。


13

name()Enumの暗黙の静的メソッドを使用してこれを行う別の方法。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

インスピレーション:Javaの列挙型の10の例


7
これは本質的valueOfにあなたのために何をします。この静的メソッドは、特別なものや例外などを提供しません。その場合、if / else構文は非常に危険です。新しい列挙型定数が追加されると、このメソッドは変更せずに中断します。
YoYo

代替名を提供するためにも、我々は大文字小文字を区別しない検索を行うためのvalueOfを使用することができ、または我々はそれの例外と採用エイリアスを回避することができますどのようにどのようにこの例を考えてみましょう:stackoverflow.com/a/12659023/744133
ヨーヨー

2
name()静的ではありません。
nrubin29 14

10

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

8

以前の回答に加えて、ヌルと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


これは、関連するパターンとEnum内でのOptionalの使用に対する本当に良い答えです。Enumもクラスであり、メソッドやオーバーライドメソッドなどで装飾できるという事実を利用しています。Fluentスタイルのプログラミングでも、メソッドから返されるnullは、その構成にバグがあります(メソッド呼び出しのFluentチェーンの未知の場所にあるNPE)。
ダレルティーグ

8

Java 8では、静的なMapパターンがさらに簡単になり、私の優先メソッドです。ジャクソンでEnumを使用したい場合は、toStringをオーバーライドして、名前の代わりに使用することができます。次に、@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);
    }
}

ジャクソンはJSON(JavaScript Object Notation)実装です。元の質問はJSONとは関係がありませんでした。
ダレルティーグ

文字列からEnumを取得することは基本的に逆シリアル化の一種であり、JSON / Jacksonがおそらく最も人気のあるシリアル化ソリューションであるため、JSONの部分は当時私が関連性があったと考えていた単なるボーナスです。
Novaterata

理解しますが、モデレートの側面から-それはOPの質問に答えるのに貢献しなかったので、そこにコンテキストを設定するのを手助けしようとしました。
ダレルティーグ

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

stackoverflow.comでの質問への回答と質問に関するガイドについては、このリンクを参照してください: stackoverflow.com/faq
bakoyaro

1
それは多かれ少なかれホセミの答えと同じです
Rup

6

ハッシュマップを使用するリサイクル生成コードから発想を得た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;
        }

}

ゼロ(0)および1の識別子は不要であることに注意してください。Enum values()メソッドは、コード化されたのと同じ順序でメンバーを返します。こうして最初のエントリは等序ゼロ、第1、あろう
ダレルティーグ

6

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

1
Enumをさらに押し上げる良い例です。標準の静的な名前とMapでのルックアップを使用して言語エンコードを作成したはずですが、それでも...本質的に同じ論理値であるものに対して異なるタグを持つ列挙型を持つ良い例です。
ダレルティーグ

5

どう?

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 Javaのすべての列挙型で使用できるいくつかの便利なメソッドを定義します。

  • name()メソッドを使用して、任意のEnum定数の名前を取得できます。列挙型定数の記述に使用される文字列リテラルは、その名前です。
  • 同様に、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を返し、その名前を呼び出すとが返されます"MALE"


4

Apacheのcommons-langライブラリには、StringをEnumタイプにマップする静的関数org.apache.commons.lang3.EnumUtils.getEnumがあります。本質的にジェフリーズと同じ答えですが、それがすでに実際に出回っているのに、なぜあなた自身のロールをするのですか?


1
公平なコメント(DRY)ですが...ほとんどのApache Commonsのものは素晴らしいですが、私はそのベースでいくつかのバグとアンチパターンを見つけました。したがって、Joshua Blochの実装は、より強力な基盤にある可能性があると言います。次に、誰かが何を実装したかを知るためにApacheコードを確認する必要があります。Javaの並行性を書き直した有名なDoug Leahと言われたら、私はそれを暗黙のうちに信頼します。
ダレルティーグ

4

役立つユーティリティを使用して、最高評価の回答に追加します...

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

  • IllegalArgumentException
  • NullPointerExeption

文字列が列挙値に確実に一致するという保証がないような要件がある場合、たとえば、文字列データがデータベースからのもので、古いバージョンの列挙が含まれている可能性がある場合は、これらを処理する必要があります。しばしば...

そこで、私が書いた再利用可能なメソッドを以下に示します。これにより、渡す文字列が一致しない場合に返されるデフォルトの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
}

2

- switchバージョンはまだ言及されていないので、紹介します(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);
      }
    }
  }

これはvalueOf(String name)メソッドに追加の値を与えないため、別の動作が必要な場合にのみ追加のメソッドを定義することは意味があります。レイズしたくない場合はIllegalArgumentException、実装を次のように変更できます。

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

デフォルト値を提供することにより 、いかなる場合も返されないような方法でをスローせずに契約を維持します。そこで我々は投げる名前がある場合とした場合には場合です。それが機能する方法です。Enum.valueOf(String name)IllegalArgumentExceptionnullNullPointerExceptionnulldefaultdefaultValuenullvalueOfOrDefault

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


1

逆の方法でキャプチャする別のユーティリティ。名前からではなく、その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、それが使用されますので、getValue固有の公開、Fooのではない最後のではなく、静的メソッドである「DREI」を、一致します。Fooに、getTranslate「drei」を返すような、finalメソッドやstaticメソッド以外のパブリックメソッドがある場合、他のメソッドを使用できますEnumUtil.from(Foo.class, "drei", "getTranslate")


1

Kotlinソリューション

拡張機能を作成して、を呼び出しますvalueOf<MyEnum>("value")。タイプが無効な場合、nullを取得して処理する必要があります

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

または、デフォルト値を設定してを呼び出しvalueOf<MyEnum>("value", MyEnum.FALLBACK)、null応答を回避することもできます。特定の列挙型を拡張して、デフォルトを自動にすることができます

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

または、両方が必要な場合は、2番目を作成します。

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

あなたの答えはここにもっと良い家があると思いますか?stackoverflow.com/questions/28548015/...
nabster

0

この種類のプロセスを使用して、コマンドを文字列として列挙に解析します。私は通常、列挙の1つを「不明」として持っているので、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;
}

-1

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.name());
        }
    }
    public static String getEnumName(String text) {
        return map.get(text.toLowerCase());
    } 
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.