Java:enumに特定の文字列が含まれているかどうかを確認しますか?


169

これが私の問題です-私は(存在する場合でも)enumに相当するものを探していArrayList.contains();ます。

これが私のコード問題のサンプルです:

enum choices {a1, a2, b1, b2};

if(choices.???(a1)}{
//do this
} 

今、私はここの方がより良いルートArrayListであるStringsことを認識していますが、列挙型のコンテンツを別の場所でスイッチ/ケースに通す必要があります。したがって、私の問題。

このようなものが存在しないと仮定すると、どうすればそれを実行できますか?


文字列を使用したスイッチ/ケースは、Java 7から実装されています
AndreyP

回答:


205

これはそれを行うはずです:

public static boolean contains(String test) {

    for (Choice c : Choice.values()) {
        if (c.name().equals(test)) {
            return true;
        }
    }

    return false;
}

この方法では、後でenum値を追加することを心配する必要がなく、すべてチェックされます。

編集:列挙型が非常に大きい場合、値をHashSetに貼り付けることができます。

public static HashSet<String> getEnums() {

  HashSet<String> values = new HashSet<String>();

  for (Choice c : Choice.values()) {
      values.add(c.name());
  }

  return values;
}

それからあなたはただ行うことができます:values.contains("your string")これはtrueまたはfalseを返します。


12
それは非常に貧弱な実装です:Choice.valueOf(test)はあなたが欲しいものです(w / try / catch)
bestsss

17
ベスト、これは明らかに最も適切なソリューションです。あるタイプのexists()メソッドを実装するために例外をスローすることは悪い習慣です。O(n)を表示しないため、実装はより効率的であると思うかもしれませんが、それは見えない基本的なフレームワークにあります。また、try {} catchを使用するとオーバーヘッドが追加されます。さらに、それは単にきれいではありません。
jluzwick、2011

25
@Jared、間違いなくvalueOf。例外をキャッチしてfalseを返すだけです。別の言い方をすれば、実装を見るとすでにMapが使用されており、JDK開発者はこれを最適化する可能性がはるかに高くなります。APIは例外をスローしますが、これは(nullを返すのではなく)議論の余地のある習慣ですが、例外をスローするAPIを処理するときは、それに伴って、ホイールを再発明しないでください。
Yishai

2
@jluzwickのtry / catchオーバーヘッドは、取得されない場合の単純なジャンプ命令であり、catchブロックで例外を使用しないことも最適化されています。パフォーマンス低下の原因となるtry / catchを恐れることは悪い習慣です。
bestss

22
contains()は、例外を除いてvalueOf()よりも優先されます。どうして?「例外は、その名前が示すように、例外的な状況でのみ使用するためのものです。通常の制御フローでは使用しないでください」(Joshua Bloch、「Effective Java」)。
james.garriss 2014年

226

代わりにApache commons lang3 libを使用してください

 EnumUtils.isValidEnum(MyEnum.class, myValue)

33
興味のある方のために、彼らが使用した基本的な実装は単にtry / catchソリューションです(@since 3.0 @version $ Id:EnumUtils.java 1199894 2011-11-09 17:53:59Z ggregory $)。
Jonathan Gawrych 2014年

1
私のコードをより単純にするので、フロー制御に例外を使用するかどうかは気にしません(実際にはそうすべきではありません)...彼らがそれを変更したとしたらすばらしいでしょう。
jpangamarca 2016


1
グアバにもこのようなソリューションが含まれていますか?
サイプレスフランケンフェルト

50

使用できます Enum.valueOf()

enum Choices{A1, A2, B1, B2};

public class MainClass {
  public static void main(String args[]) {
    Choices day;

    try {
       day = Choices.valueOf("A1");
       //yes
    } catch (IllegalArgumentException ex) {  
        //nope
  }
}

チェックが頻繁に失敗することが予想される場合は、他の例が示しているように単純なループを使用した方がよい場合があります-enumに多くの値が含まれている場合は、おそらくbuilda HashSetまたは同様のenum値が文字列に変換され、HashSet代わりにクエリを実行します。


8
そのような場合、例外は最良の選択だとは思いません。
GokcenG 2014

6
トライアンドキャッチは最後の手段です。Try and Catchは高額です
Jesus Dimrix

2
ビジネスロジックを実行するためにランタイム例外に依存することは、費用がかかるだけでなく、読みにくいものです。チェックされた例外に関しては、それらがビジネスの一部となるため、異なります。
ルイスソアレス2015年

2
これにより、再試行されている実際の例外的なケースを見つけるために、スローされた例外に対して広範なブレークをオンにすることもできなくなります。(または少なくともそうすることは非常に煩わしくなります)。例外的なケースには例外を使用します。
Nickolay Kondratyev 2016

4
EnumUtils.isValidEnum(MyEnum.class, myValue)同様のロジックとIMOを使用して、この簡単なタスク用のライブラリ全体を追加することは理にかなっています
Vikramjit Roy

37

Java 1.8を使用している場合は、Stream + Lambdaを選択してこれを実装できます。

public enum Period {
    DAILY, WEEKLY
};

//This is recommended
Arrays.stream(Period.values()).anyMatch((t) -> t.name().equals("DAILY1"));
//May throw java.lang.IllegalArgumentException
Arrays.stream(Period.values()).anyMatch(Period.valueOf("DAILY")::equals);

19

さらに良い:

enum choices {
   a1, a2, b1, b2;

  public static boolean contains(String s)
  {
      for(choices choice:values())
           if (choice.name().equals(s)) 
              return true;
      return false;
  } 

};

楽観的な解決策をありがとう
Parth Patel

19

Guavas Enumsがあなたの友達かもしれません

例えばこのように:

enum MyData {
    ONE,
    TWO
}

@Test
public void test() {

    if (!Enums.getIfPresent(MyData.class, "THREE").isPresent()) {
        System.out.println("THREE is not here");
    }
}

11

最初に列挙型をリストに変換してから、リストに含まれるメソッドを使用できます

enum Choices{A1, A2, B1, B2};

List choices = Arrays.asList(Choices.values());

//compare with enum value 
if(choices.contains(Choices.A1)){
   //do something
}

//compare with String value
if(choices.contains(Choices.valueOf("A1"))){
   //do something
}

これは受け入れられる答えになるはずです。リストへの変換は、それを行う最もクリーンな方法です。これは、Javaでの「例外の適切な使用」に関する全体(側面)の議論を、ここの他の回答で省略します。
マヌエル、

値が存在しない場合は、IllegalArgumentExceptionをスローします。
mkyong

10

いくつかの仮定:
1)例外的なフロー制御であるため、try / catchはありません

3)スペースに制限がない(通常のソリューションでは一般的)

import java.util.HashSet;
import java.util.Set;

enum Choices {
    a1, a2, b1, b2;

    private static Set<String> _values = new HashSet<>();

    // O(n) - runs once
    static{
        for (Choices choice : Choices.values()) {
            _values.add(choice.name());
        }
    }

    // O(1) - runs several times
    public static boolean contains(String value){
        return _values.contains(value);
    }
}

10

ここではいくつかのライブラリーについて言及しましたが、私が実際に探していたライブラリー、Springが欠けています。

ありObjectUtils#containsConstantデフォルトではケース鈍感であるが、あなたがしたい場合は厳しいことができます。これは次のように使用されます:

if(ObjectUtils.containsConstant(Choices.values(), "SOME_CHOISE", true)){
// do stuff
}

注:ここではオーバーロードメソッドを使用して、大文字と小文字を区別するチェックの使用方法を示しました。ブール値を省略して、大文字と小文字を区別しない動作にすることができます。

ただし、大きな列挙型には注意してください。一部のようにMap実装を使用していないためです...

おまけとして、valueOfの大文字と小文字を区別しないバリアントも提供します:ObjectUtils#caseInsensitiveValueOf


7

これを使えます

YourEnum {A1、A2、B1、B2}

boolean contains(String str){ 
    return Sets.newHashSet(YourEnum.values()).contains(str);
}                                  

@ wightwulf1944によって提案された更新は、ソリューションをより効率的にするために組み込まれています。


4
この実装は非効率的です。これは、列挙値を反復処理して新しいセットを作成し、次にストリームを作成して、結果のセットを反復処理します。これは、関数が呼び出されるたびに新しいセットとストリームが作成されるstream()ことを意味し、セットで使用すると、基になるハッシュテーブルを利用するのではなく、セット内の各要素を反復することになります。これを改善するには、作成されたセットをキャッシュして、contains()代わりにそのメソッドを使用するのが最善です。ストリームを取得する必要がある場合は、Arrays.stream()代わりに使用してください。
田代スバル2017年

3

あるとは思いませんが、次のようなことができます。

enum choices {a1, a2, b1, b2};

public static boolean exists(choices choice) {
   for(choice aChoice : choices.values()) {
      if(aChoice == choice) {
         return true;
      }
   }
   return false;
}

編集:

リチャードのように文字列を使用するように変換しないと機能しないので、リチャードのバージョンをご覧ください。


OPは文字列をテストしたいと思いますか?
リチャードH

ええ、ハハ。列挙型に選択肢があることはすでにわかっているので、この方法はそれほど効果的ではありません。修正はより正確です。
jluzwick、2011

1
列挙自体のサブセット(名前ではなく)を操作する場合は、EnumSetを確認することをお勧めします。download.oracle.com/javase/6/docs/api/java/util/EnumSet.html
Yishai

おそらくばかげた質問かもしれませんが、download.oracle.com / javase / 6 / docs / api / java / lang / Enum.htmlに.values()文書化されていないのはなぜですか?
匿名

それは素晴らしい質問です。あなたはそうです、それはドキュメンテーションには存在せず、Enumソースにも存在しません。Enumの実装の1つに存在するか、それを許可するJLSルールがあると想定しています。また、すべてのコレクションオブジェクトにはこれがあり、必ずしもコレクションを実装しているわけではありませんが、これはコレクションと見なすことができます。
jluzwick、2011

3

Java Streamsはそのためのエレガントな方法を提供します

Stream.of(MyEnum.values()).anyMatch(v -> v.name().equals(strValue))

戻り値:ストリームの要素が指定された値と一致する場合はtrue、そうでない場合はfalse


2

Pabloの応答をvalueOf()と組み合わせてみませんか?

public enum Choices
{
    a1, a2, b1, b2;

    public static boolean contains(String s) {
        try {
            Choices.valueOf(s);
            return true;
        } catch (Exception e) {
            return false;
        }
}

しないでください。あなたと同じである他の古い回答を参照してください:stackoverflow.com/a/4936872/103412
Torsten

1

このアプローチはEnum、をチェックするために使用でき、Utilsクラスに追加できます。

public static <T extends Enum<T>> boolean enumContains(Class<T> enumerator, String value)
{
    for (T c : enumerator.getEnumConstants()) {
        if (c.name().equals(value)) {
            return true;
        }
    }
    return false;
}

次のように使用します。

boolean isContained = Utils.enumContains(choices.class, "value");

1

この検証のために次のクラスを作成しました

public class EnumUtils {

    public static boolean isPresent(Enum enumArray[], String name) {
        for (Enum element: enumArray ) {
            if(element.toString().equals(name))
                return true;
        }
        return false;
    }

}

使用例:

public ArrivalEnum findArrivalEnum(String name) {

    if (!EnumUtils.isPresent(ArrivalEnum.values(), name))
        throw new EnumConstantNotPresentException(ArrivalEnum.class,"Arrival value must be 'FROM_AIRPORT' or 'TO_AIRPORT' ");

    return ArrivalEnum.valueOf(name);
}

0

valueOf("a1")文字列で検索したい場合に使用できます


3
しかし、それはエレガントではありません。値が存在しない場合は、例外がスローされます。だから、おそらくあなたはそれをトライキャッチで囲む必要があります
Kasturi

値が存在しない場合は例外がスローされます
Richard H

一致するオブジェクトを探す列挙型の選択を繰り返すよりもエレガントではありませんか?
jprete

0

これは列挙型であり、これらは定数値であるため、switchステートメント内で次のようなことを行っている場合:

case: val1
case: val2

また、定数として宣言されているものを知る必要があるのはなぜですか?


このコードは、上記のswitchステートメントには含まれていません。この場合、代わりにArrayListを使用することを他の人が提案しているため、列挙型が必要であると単に述べていました。
Jared

@Jaredは今ではもっと理にかなっています
Woot4Moo

@Jaredが存在する値をすでに知っているので、それは実際には重要ではありません。基本的に、list.contains()に相当する列挙型はMyEnum.MyAwesomeValue
Woot4Moo

0

グアバを使用すると、さらに簡単になります。

boolean isPartOfMyEnum(String myString){

return Lists.newArrayList(MyEnum.values().toString()).contains(myString);

}

以下のようkioriaが、これは動作しませんと述べました。MyEnum.values()MyEnumインスタンスの配列をMyEnum.value().toString()返し、この配列オブジェクトの文字列表現( "[LMyEnum; @ 15b94ed3"のような文字列のみ)を返します
user2137020

(デフォルトのtoStringメソッドをオーバーライドしない限り)の.name()代わりに呼び出す必要があり.toString()ます。詳細はこちらをご覧ください:enum .name()と.toString()の
違い

0

これは、以前の方法のすべてのアプローチを組み合わせたものであり、同等のパフォーマンスが得られます。任意の列挙型に使用でき、@ Richard Hの「編集」ソリューションをインライン化し、@ bestsssなどの無効な値には例外を使用します。唯一のトレードオフは、クラスを指定する必要があるということですが、これにより2行になります。

import java.util.EnumSet;

public class HelloWorld {

static enum Choices {a1, a2, b1, b2}

public static <E extends Enum<E>> boolean contains(Class<E> _enumClass, String value) {
    try {
        return EnumSet.allOf(_enumClass).contains(Enum.valueOf(_enumClass, value));    
    } catch (Exception e) {
        return false; 
    }
}

public static void main(String[] args) {
    for (String value : new String[] {"a1", "a3", null}) {
        System.out.println(contains(Choices.class, value));
    }
}

}


0
com.google.common.collect.Sets.newHashSet(MyEnum.values()).contains("myValue")

0

値が存在するかどうかを確認するソリューションと同様に列挙値を取得する:

protected TradeType getEnumType(String tradeType) {
    if (tradeType != null) {
        if (EnumUtils.isValidEnum(TradeType.class, tradeType)) {
            return TradeType.valueOf(tradeType);
        }
    }
    return null;
}

0

これは私のために働きます:

Arrays.asList(YourEnum.values()).toString().contains("valueToCheck");

3
YourEnumに「valueToCheckBlaBla」が含まれている場合でも、バージョン全体はtrueを返します。これは、「valueToCheck」がリスト全体の文字列表現に存在するためです。
Nicko

0

Java 8以上を使用している場合、これを行うことができます。

boolean isPresent(String testString){
      return Stream.of(Choices.values()).map(Enum::name).collect(Collectors.toSet()).contains(testString);
}


0

あなたはそれをcontainsメソッドとして作ることができます:

enum choices {a1, a2, b1, b2};
public boolean contains(String value){
    try{
        EnumSet.allOf(choices.class).contains(Enum.valueOf(choices.class, value));
        return true;
    }catch (Exception e) {
        return false;
    }
}

または、コードブロックで使用することもできます。

try{
    EnumSet.allOf(choices.class).contains(Enum.valueOf(choices.class, "a1"));
    //do something
}catch (Exception e) {
    //do something else
}

0

次も使用できます:com.google.common.base.Enums

Enums.getIfPresent(varEnum.class、varToLookFor)はオプションを返します

Enums.getIfPresent(fooEnum.class、myVariable).isPresent()?Enums.getIfPresent(fooEnum.class、myVariable).get:fooEnum.OTHERS


0

私はただ書いて、

Arrays.stream(Choice.values()).map(Enum::name).collect(Collectors.toList()).contains("a1");

Enum#equalsはオブジェクト比較でのみ機能します。


-1
public boolean contains(Choices value) {
   return EnumSet.allOf(Choices.class).contains(value);
}

それは動作しません。文字列をチェックしている間、セットには列挙オブジェクトがあります。
iTake 2013年

Stringについてだったので、答えは質問に適合しません:)
iTake

-11

enumJavaではかなり強力です。contains(クラスにメソッドを追加するのと同じように)enumにメソッドを簡単に追加できます。

enum choices {
  a1, a2, b1, b2;

  public boolean contains(String s)
  {
      if (s.equals("a1") || s.equals("a2") || s.equals("b1") || s.equals("b2")) 
         return true;
      return false;
  } 

};

もしかして s.equals("b1") || s.equals("b2")??
Jigar Joshi、2011

3
s.equals("xx")後で追加する列挙型ごとに新しいものを追加する必要があるため、これはおそらくそれを行うための最良の方法ではありません。
jluzwick、2011

1
そして、1000以上の列挙型があります。
Jared、

20
このような恐ろしい解決策を提案する人々はどのようにして64Kの評判を得ますか?私はこの貢献者の答えに基づいてそこに
投げ込ま
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.