2009-10-02 107 views
18

我想查找一个枚举集,知道经常会有一个不匹配抛出异常:我想检查之前执行查找值存在,以避免例外。我的枚举看起来是这样的:使用枚举之前检查有效的枚举值

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

,我要检查如果说,“香蕉”是我的枚举值的一个尝试使用相关枚举之前。我可以通过我的比较字符串中的允许值重复,以

Fruit.values()[i].fruitname 

,但我希望能够像做(pseduo码):

if (Fruit.values().contains(myStringHere)) {... 

这可能吗?我应该完全使用别的东西吗(Arrays?Maps?)?

编辑:最后我已经用了NawaMan的建议,但是感谢大家对所有有用的输入。

回答

22

我真的不知道内置的解决方案。所以你可能必须自己写一个静态方法。

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; 
    } 
    ... 
} 
+5

“values()”每次都会创建一个克隆数组,因此最好不要经常调用它。只调用一次并缓存结果,或使用“EnumSet.allOf(Fruit.class)”。 – dogbane 2010-03-30 13:10:33

+1

在JDK 1.7上已修复。在JDK 1.5中,稍后有解决此问题的评论。不知道JDK 1.6中会发生什么。 – alexsmail 2012-02-09 16:24:24

+1

请注意,此解决方案对于许多值而言速度很慢。相反,最好做一些像http://stackoverflow.com/a/2546726/260805。 – Ztyx 2015-04-09 08:33:36

7

当我这样做时,我通常将它移植到我的枚举类。

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

但是:

  • 对于小枚举它可能是更有效的步骤在列表中。

顺便说一句:

  • 在这种情况下,我会去与惯例和使用的域名(),因为它是相同的,不同之处的情况下的自定义名称
  • 该解决方案(容易固定。)当你要查找的内容与name()值完全不同时更有用。
+0

我把权限来修复例如,具有地图为静态。 – KLE 2009-10-02 13:58:44

+0

初始化顺序可以,请不要担心。 – KLE 2009-10-02 14:13:41

+0

是的,缺乏静电是一个错字。 – Trejkaz 2009-10-03 08:51:10

2

我同意你没有创建任何异常的愿望。这对于性能很有帮助(因为构建堆栈跟踪的例外是值得一千条指令的),并且当您说它通常是找不到它的时候是合乎逻辑的(因此,它不是例外条件) 。


我认为你提到的for loop是正确的,如果你只有一些枚举值。它可能会有最好的表现。但我明白你不需要它。


您可以构建一个Map来查找枚举值,这样可以避免异常并同时返回相应的枚举值。

更新:Trejkaz已经发布了这样做的代码。


还要注意的是,有时,而不是返回null因为没有实例相匹配时,返回类型,一些枚举有一个专用实例(称之为空或NOT_FOUND为例)。优点是所有的调用代码都不需要处理空值,并且没有风险NullPointerException。如果需要,可以使用布尔方法isFound()(除了该实例外,返回true)。而那些真正需要区分他人价值的代码仍然可以,而那些不关心的代码只是在没有这种特殊情况的知识的情况下通过实例。

+2

Touche。与“不是特殊情况”打个电话。我在想,一个例外应该被视为如此。如果它不是一个真正的例外,它不应该是一个例外。 +1,@KLE。 – Rap 2009-10-02 14:05:28

5

我会在这里逆势而行......我认为你的第一个冲动(抛出异常)是正确的。

如果您在业务逻辑而不是用户界面内进行检查,那么在该级别将不会有任何反馈给用户。 (如果你没有在UI中检查,我们有其他问题)。因此,处理它的正确方法是抛出异常。

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

简而言之,你是第一个想到的钱。去吧。只是改变你的异常处理有点不同。

2

也许你不应该使用枚举?如果你经常需要处理Enum中没有定义的值,也许你应该使用类似于HashMap的东西< String,Fruit >然后你可以使用containsKey()来找出一个特定的键是否存在。

2

只要提一下让你的调用代码不必担心异常或条件检查的另一种可能性就是总是返回一个Fruit。例如,如果找不到该字符串,则返回Fruit.UNKNOWN。

例子:

public enum Fruit { 
    public Fruit getValueOf(String name) { 
     for (Fruit fruit : Fruit.values()) { 
      if (fruit.fruitname.equals(name)) 
       return fruit; 
      } 
     } 
     return UNKNOWN; 
    } 
    ... 
} 
5

这是如何使用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); 
    } 
} 
12

有一个Apache Commons Lang中EnumUtils.isValidEnum()。不幸的是,引擎盖下,这是使用try/catch语句的逻辑,并返回boolean值,但至少你的代码看起来干净:

if(EnumUtils.isValidEnum(Fruit.class, fruitname)) { .... 

您需要使用最新的commons-lang3库作为公共琅2.X没有这个功能。

+0

也检查空值,这已经足够了。感谢您的评论有帮助 – 2013-03-26 19:13:38

+1

我不知道这个功能。这真的是最清楚和最简单的方法(如果你有依赖) – Seega 2014-09-01 09:03:32

+0

它不检查值。例如如果有一个苹果(“苹果”),并且该调用是苹果,它将返回false。如果该呼叫是APPLE,它将返回true。 – Dejell 2015-09-17 12:08:55

3

这是我的解决方案。我创建了一个集合,以便您不必指定构造函数。这还具有附加的好处,即查找的值必须与枚举的情况相匹配。

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

} 
2

在java8你可以做这样的

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