Java:检查枚举是否包含给定的字符串?

Jar*_*red 142 java string enums

这是我的问题 - 我正在寻找(如果它甚至存在)枚举相当于ArrayList.contains();.

这是我的代码问题的示例:

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

if(choices.???(a1)}{
//do this
} 
Run Code Online (Sandbox Code Playgroud)

现在,我意识到一个ArrayListStrings会在这里更好的路线,但我通过一个开关/箱其他地方运行我的枚举的内容.因此我的问题.

假设不存在这样的事情,我怎么能去做呢?

小智 206

请改用Apache commons lang3 lib

 EnumUtils.isValidEnum(MyEnum.class, myValue)
Run Code Online (Sandbox Code Playgroud)

  • 注意那些感兴趣的人,他们使用的底层实现只是try/catch解决方案(@since 3.0 @version $ Id:EnumUtils.java 1199894 2011-11-09 17:53:59Z ggregory $). (31认同)
  • 使我的代码更简单,所以我不在乎它是否使用异常进行流量控制(他们真的不应该)...如果他们改变这一点那就太好了。 (2认同)
  • 番石榴也含有这样的溶液吗? (2认同)

Ric*_*d H 185

这应该这样做:

public static boolean contains(String test) {

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

    return false;
}
Run Code Online (Sandbox Code Playgroud)

这意味着您不必担心以后添加额外的枚举值,它们都会被检查.

编辑:如果枚举非常大,您可以将值粘贴在HashSet中:

public static HashSet<String> getEnums() {

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

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

  return values;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以做:values.contains("your string")返回true或false.

  • @Jared,绝对值得.抓住你的异常并返回false.对于那些说不然的人,如果你看一下实现,它已经使用了Map,而且JDK开发人员有更好的机会来优化它.API抛出异常,这是一个有争议的做法(而不是返回null),但是当你处理抛出异常的API时,请使用它,不要重新发明轮子. (24认同)
  • contains()优先于valueOf(),但有异常.为什么?因为"正如其名称暗示的那样,例外仅用于特殊条件;它们永远不应用于普通控制流程"(Joshua Bloch,"Effective Java"). (21认同)
  • 最好的,这显然是最合适的解决方案.抛出异常来实现一种exists()方法是不好的做法.虽然你可能认为你的实现更有效,因为它没有看O(n),但它在底层框架中是不可见的.使用try {} catch也增加了开销.而且,它只是不漂亮. (15认同)
  • 这是一个非常糟糕的impl.:Choice.valueOf(test)就是你想要的(带有try/catch) (10认同)
  • @jluzwick try/catch开销是一个简单的跳转指令,不采取时,不使用catch块中的Exception也进行了优化.担心尝试/捕捉失去性能的原因是一种不好的做法. (2认同)
  • @bestsss我会告诉你,使用try {} catch来优化并增加可忽略的开销但是在你的例子中使用try {} catch通常被认为是不好的做法,请参阅http://stackoverflow.com/问题/ 3515618 /不同风格的程序流程.由于我们可以在不引入任何错误的情况下保证内部Java代码的相同性能,因此我们应该执行上述操作.这是因为它比使用try {} catch更清晰,更清晰. (2认同)
  • @james.garriss 在我看来,Java 中异常的目的非常值得商榷。创建“新 URL”时的“MalformedURLException”只是无数示例之一。创建一个没有 `try/catch` 的 `URL` 甚至会引发编译器警告。由于历史原因,Java 在设计上依赖于“try/catch”。所以说`try/catch` 不应该用于控制应用程序流似乎更像是一种愿望而不是现实。我同意不应该使用它,但是由于其遗留问题,Java 可能只是错误的语言。 (2认同)

nos*_*nos 47

您可以使用 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
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望检查经常失败,您可能最好使用其他已显示的简单循环 - 如果您的枚举包含许多值,可能是builda HashSet或类似的枚举值转换为字符串HashSet而是查询.

  • 在这种情况下,我不认为异常是最好的选择. (5认同)
  • 尝试和捕获应该是最后的手段.尝试和捕获是昂贵的 (4认同)
  • `EnumUtils.isValidEnum(MyEnum.class,myValue)`使用类似的逻辑和IMO,为这个琐碎的任务添加整个库确实有意义 (4认同)
  • 依靠运行时异常来执行业务逻辑,除了成本高昂之外,可读性也不强。关于检查异常,它是不同的,因为它们构成了业务的一部分。 (3认同)
  • 这也可以防止任何人在抛出异常时开启广泛的中断,以找到正在重试的实际例外情况.(或者至少让它非常烦人).对例外情况使用例外. (2认同)

Hao*_* Ma 27

如果您使用的是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);
Run Code Online (Sandbox Code Playgroud)


H6.*_*H6. 18

Guavas Enums可能是你的朋友

像这样:

enum MyData {
    ONE,
    TWO
}

@Test
public void test() {

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


小智 16

更好的是:

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

};
Run Code Online (Sandbox Code Playgroud)


Bik*_*ram 9

您可以先将枚举转换为List,然后使用list contains方法

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
}
Run Code Online (Sandbox Code Playgroud)

  • 如果该值不存在,则抛出 IllegalArgumentException。 (2认同)

Pim*_*oek 9

这里提到了几个图书馆,但我想念我真正想要的那个:春天!

还有就是ObjectUtils#containsConstant这是不区分大小写的默认,但如果你希望能严格.它是这样使用的:

if(ObjectUtils.containsConstant(Choices.values(), "SOME_CHOISE", true)){
// do stuff
}
Run Code Online (Sandbox Code Playgroud)

注意:我在这里使用了重载方法来演示如何使用区分大小写的检查.您可以省略布尔值以使用不区分大小写的行为.

但要注意大型枚举,因为他们不像某些人那样使用Map实现...

作为奖励,它还提供了valueOf的一个不区分大小写的变体:ObjectUtils #caseInsensitiveValueOf


gre*_*ror 7

你可以用它

YourEnum {A1,A2,B1,B2}

boolean contains(String str){ 
    return Sets.newHashSet(YourEnum.values()).contains(str);
}                                  
Run Code Online (Sandbox Code Playgroud)

@ wightwulf1944建议更新,以提高解决方案的效率.

  • 这种实现效率很低.这将遍历枚举值以创建新集,然后创建一个流,该流迭代结果集.这意味着每次调用函数时都会创建一个新的Set和Stream,并且在set上使用`stream()`意味着您正在迭代集合中的每个元素,而不是利用更快的底层哈希表.要改进这一点,最好缓存创建的Set并使用它的`contains()`方法.如果必须获取流,请使用`Arrays.stream()`. (4认同)

And*_*eyP 6

几个假设:
1)没有尝试/捕获,因为它是特殊的流量控制
2)'包含'方法必须快速,因为它通常运行几次.
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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Sou*_*abh 6

Java Streams 提供了一种优雅的方式来做到这一点

Stream.of(MyEnum.values()).anyMatch(v -> v.name().equals(strValue))
Run Code Online (Sandbox Code Playgroud)

返回: 如果流的任何元素与提供的值匹配,则为 true,否则为 false