web-dev-qa-db-ja.com

String値からJava enumを検索するにはどうすればよいですか?

文字列値(またはその他の値)から列挙型を検索したいと思います。次のコードを試しましたが、初期化子で静的を許可していません。簡単な方法はありますか?

public enum Verbosity {

    BRIEF, NORMAL, FULL;

    private static Map<String, Verbosity> stringMap = new HashMap<String, Verbosity>();

    private Verbosity() {
        stringMap.put(this.toString(), this);
    }

    public static Verbosity getVerbosity(String key) {
        return stringMap.get(key);
    }
};
133

列挙ごとに自動的に作成されるvalueOfメソッドを使用します。

Verbosity.valueOf("BRIEF") == Verbosity.BRIEF

任意の値の場合:

public static Verbosity findByAbbr(String abbr){
    for(Verbosity v : values()){
        if( v.abbr().equals(abbr)){
            return v;
        }
    }
    return null;
}

プロファイラーから指示があった場合のみ、後でMapの実装に進みます。

私はそれがすべての値を反復していることを知っていますが、3つの列挙値だけで他の努力の価値はほとんどありません。実際、あなたが多くの値を持っていない限り、マップで気にしないでしょう、それは十分に高速です。

208
Gareth Davis

あなたは近いです。任意の値については、次のようなものを試してください。

public enum Day { 

    MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
    THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;

    private final String abbreviation;

    // Reverse-lookup map for getting a day from an abbreviation
    private static final Map<String, Day> lookup = new HashMap<String, Day>();

    static {
        for (Day d : Day.values()) {
            lookup.put(d.getAbbreviation(), d);
        }
    }

    private Day(String abbreviation) {
        this.abbreviation = abbreviation;
    }

    public String getAbbreviation() {
        return abbreviation;
    }

    public static Day get(String abbreviation) {
        return lookup.get(abbreviation);
    }
}
121
Lyle

Java 8では、次の方法で実現できます。

public static Verbosity findByAbbr(final String abbr){
    return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}
15
Lam Le

@Lyleの答えはかなり危険です。列挙型を静的な内部クラスにすると、特に動作しないことがわかりました。代わりに、列挙の前にBootstrapSingletonマップをロードするこのようなものを使用しました。

編集これは、最新のJVM(JVM 1.6以上)ではもう問題ではないはずですが、JRebelにはまだ問題があると思いますが、私は持っていません再テストする機会

最初にロードしてください:

   public final class BootstrapSingleton {

        // Reverse-lookup map for getting a day from an abbreviation
        public static final Map<String, Day> lookup = new HashMap<String, Day>();
   }

次に、enumコンストラクターでロードします。

   public enum Day { 
        MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
        THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;

        private final String abbreviation;

        private Day(String abbreviation) {
            this.abbreviation = abbreviation;
            BootstrapSingleton.lookup.put(abbreviation, this);
        }

        public String getAbbreviation() {
            return abbreviation;
        }

        public static Day get(String abbreviation) {
            return lookup.get(abbreviation);
        }
    }

内部列挙型がある場合、列挙型定義の上にMapを定義するだけで、(理論的には)前にロードされるはずです。

13
Adam Gent

valueOf() ?は使用できません

編集:ところで、列挙型で静的{}を使用することを妨げるものは何もありません。

6
Fredrik

Java Language Specification 7には !があります。これは、自己参照を使用したマップの初期化に関する質問を反映しています。

5
mbonato

他の人に役立つ場合は、ここにリストされていない、私が好むオプションは GuavaのMaps機能 を使用します:

public enum Vebosity {
    BRIEF("BRIEF"),
    NORMAL("NORMAL"),
    FULL("FULL");

    private String value;
    private Verbosity(final String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    private static ImmutableMap<String, Verbosity> reverseLookup = 
            Maps.uniqueIndex(Arrays.asList(Verbosity.values()), Verbosity::getValue);

    public static Verbosity fromString(final String id) {
        return reverseLookup.getOrDefault(id, NORMAL);
    }
}

デフォルトでは、nullを使用できます。throw IllegalArgumentExceptionまたはfromStringは、Optionalを返すことができます。

4
Chad Befus

おそらく、これを見てください。私のために働いています。これの目的は、「/ red_color」で「RED」を検索することです。 static mapを宣言し、enumsを一度だけロードすると、enumsが多い場合にパフォーマンス上の利点が得られます。

public class Mapper {

public enum Maps {

    COLOR_RED("/red_color", "RED");

    private final String code;
    private final String description;
    private static Map<String, String> mMap;

    private Maps(String code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getCode() {
        return name();
    }

    public String getDescription() {
        return description;
    }

    public String getName() {
        return name();
    }

    public static String getColorName(String uri) {
        if (mMap == null) {
            initializeMapping();
        }
        if (mMap.containsKey(uri)) {
            return mMap.get(uri);
        }
        return null;
    }

    private static void initializeMapping() {
        mMap = new HashMap<String, String>();
        for (Maps s : Maps.values()) {
            mMap.put(s.code, s.description);
        }
    }
}
}

ご意見をお聞かせください。

1
Midhun

次のコードとして列挙を定義できます:

public enum Verbosity 
{
   BRIEF, NORMAL, FULL, ACTION_NOT_VALID;
   private int value;

   public int getValue()
   {
     return this.value;
   } 

   public static final Verbosity getVerbosityByValue(int value)
   {
     for(Verbosity verbosity : Verbosity.values())
     {
        if(verbosity.getValue() == value)
            return verbosity ;
     }

     return ACTION_NOT_VALID;
   }

   @Override
   public String toString()
   {
      return ((Integer)this.getValue()).toString();
   }
};

詳細については次のリンクを参照

0
Vinay Sharma

Java 8以降では、静的ブロックなしで1行でマップを初期化できます。

private static Map<String, Verbosity> stringMap = Arrays.stream(values())
                 .collect(Collectors.toMap(Enum::toString, Function.identity()));
0
Adrian