在使用枚举之前检查有效的枚举值

dav*_*vek 23 java enums

我正在尝试查找枚举集,知道通常会有一个不匹配的异常抛出:我想在执行查找之前检查值是否存在以避免异常.我的枚举看起来像这样:

public enum Fruit {
    APPLE("apple"),
    ORANGE("orange");
    ;
    private final String fruitname;
    Fruit(String fruitname) {
        this.fruitname = fruitname;
    }
    public String fruitname() {return fruitname;}
}
Run Code Online (Sandbox Code Playgroud)

我想在尝试使用相关的枚举之前检查"香蕉"是否是我的枚举值之一.我可以迭代比较我的字符串的允许值

Fruit.values()[i].fruitname
Run Code Online (Sandbox Code Playgroud)

但我希望能够做类似的事情(pseduo-code):

if (Fruit.values().contains(myStringHere)) {...
Run Code Online (Sandbox Code Playgroud)

那可能吗?我应该完全使用其他东西(阵列?地图?)?

编辑:最后我和NawaMan的建议一致,但感谢所有人提供了有用的建议.

Naw*_*Man 26

我真的不知道内置的解决方案.因此,您可能必须自己编写静态方法.

public enum Fruit {
   ...
   static public boolean isMember(String aName) {
       Fruit[] aFruits = Fruit.values();
       for (Fruit aFruit : aFruits)
           if (aFruit.fruitname.equals(aName))
               return true;
       return false;
   }
   ...
}
Run Code Online (Sandbox Code Playgroud)

  • "values()"每次都会创建一个克隆数组,因此最好不要经常调用它.只调用一次并缓存结果,或使用"EnumSet.allOf(Fruit.class)". (6认同)

小智 20

有一个apache commons lang EnumUtils.isValidEnum().不幸的是,在幕后,这是使用try/catch逻辑并返回布尔值,但至少你的代码看起来很干净:

if(EnumUtils.isValidEnum(Fruit.class, fruitname)) { ....
Run Code Online (Sandbox Code Playgroud)

您将需要使用最新的commons-lang3库作为commons-lang 2.x没有此功能.

  • 它不检查该值。例如,如果有 APPLE("apple"),并且调用是针对 apple 的,则它将返回 false。如果调用的是 APPLE,它将返回 true。 (3认同)

Tre*_*kaz 8

当我这样做时,我通常把它移植到我的枚举课上.

public enum Fruit {
        APPLE("apple"),
        ORANGE("orange");

    // Order of initialisation might need adjusting, I haven't tested it.
    private static final Map<String, Fruit> lookup = new HashMap<String, Fruit>();
    private final String fruitname;
    Fruit(String fruitname) {
        this.fruitname = fruitname;
        lookup.put(fruitname, Fruit);
    }
    public String fruitname() {return fruitname;}

    public static Fruit fromFruitname(String fruitname) {
        return lookup.get(fruitname);
    }
}
Run Code Online (Sandbox Code Playgroud)

但:

  • 对于小型枚举,单步列表可能更有效.

偶然:

  • 在这种情况下,我会使用约定并使用name(),因为它与自定义名称相同,除了案例(容易修复).
  • 当您需要查找的内容与name()值完全不同时,此解决方案更有用.

  • 我无法得到这个例子,因为我得到"无法引用初始化器中的静态枚举字段<myclass> .Fruit.lookup".如果我使地图非静态,那么来自Fruitname的标注会抱怨"无法对非静态字段查找进行静态引用".我错过了什么? (2认同)

dog*_*ane 7

这是使用EnumSet.allOf填充地图的方法:

public enum Fruit {

    APPLE("apple"), 
    ORANGE("orange");

    private static final Map<String, Fruit> nameToValueMap = new HashMap<String, Fruit>();

    static {
        for (Fruit value : EnumSet.allOf(Fruit.class)) {
            nameToValueMap.put(value.name(), value);
        }
    }

    private final String fruitname;

    Fruit(String fruitname) {
        this.fruitname = fruitname;
    }

    public String fruitname() {
        return fruitname;
    }

    public static Fruit forName(String name) {
        return nameToValueMap.get(name);
    }
}
Run Code Online (Sandbox Code Playgroud)


Yei*_*son 7

这是我的解决方案.我创建了一个集合,因此您不必指定构造函数.这也有额外的好处,即查找的值必须与枚举的情况相匹配.

public enum Fruit{
    Apple, 
    Orange;

    private final static Set<String> values = new HashSet<String>(Fruit.values().length);

    static{
        for(Fruit f: Fruit.values())
            values.add(f.name());
    }

    public static boolean contains( String value ){
        return values.contains(value);
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。简明扼要。 (2认同)

Rap*_*Rap 5

我会在这里成为逆势者...我认为你的第一个冲动(抛出异常)是正确的做法.

如果您在业务逻辑而不是UI中进行检查,则该级别不会向用户提供任何反馈.(如果您没有在UI中检查,我们还有其他问题).因此,处理它的正确方法是抛出异常.

当然,这并不意味着您必须将异常气泡升级到UI级别,从而使其余逻辑短路.我通常做的是将枚举赋值放在它自己的小try-catch中,并通过重新分配或者你设计的任何其他优雅解决方案来处理异常.

简而言之......你第一次想到的就是钱.去吧.只需更改您的异常处理有点不同.


cha*_*rlb 5

在java8中你可以这样做

 public static boolean isValidFruit(final String fruit) {
    return Arrays.stream(Fruit.values())
        .map(Fruit::name)
        .collect(Collectors.toSet())
        .contains(fruit);
}
Run Code Online (Sandbox Code Playgroud)