Java 在使用枚举之前检查有效的枚举值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1509614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Check valid enum values before using enum
提问by davek
I'm trying to lookup against an Enum set, knowing that there will often be a non-match which throws an exception: I would like to check the value exists before performing the lookup to avoid the exceptions. My enum looks something like this:
我正在尝试针对 Enum 集进行查找,知道通常会出现不匹配的情况,从而引发异常:我想在执行查找之前检查该值是否存在以避免异常。我的枚举看起来像这样:
public enum Fruit {
APPLE("apple"),
ORANGE("orange");
;
private final String fruitname;
Fruit(String fruitname) {
this.fruitname = fruitname;
}
public String fruitname() {return fruitname;}
}
and I want to check if, say, "banana" is one of my enum values before attempting to use the relevant enum. I could iterate through the permissible values comparing my string to
并且我想在尝试使用相关枚举之前检查“香蕉”是否是我的枚举值之一。我可以遍历允许的值,将我的字符串与
Fruit.values()[i].fruitname
but I'd like to be able to do something like (pseduo-code):
但我希望能够做类似(伪代码)的事情:
if (Fruit.values().contains(myStringHere)) {...
Is that possible? Should I be using something else entirely (Arrays? Maps?)?
那可能吗?我应该完全使用其他东西(数组?地图?)?
EDIT: in the end I've gone with NawaMan's suggestion, but thanks to everyone for all the helpful input.
编辑:最后我接受了 NawaMan 的建议,但感谢大家提供的所有有用的意见。
采纳答案by NawaMan
I really don't know a built-in solution. So you may have to write it yourself as a static method.
我真的不知道内置的解决方案。因此,您可能必须自己将其编写为静态方法。
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;
}
...
}
回答by Trejkaz
When I do this I usually graft it onto my enum class.
当我这样做时,我通常将它移植到我的枚举类中。
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);
}
}
But:
但:
- For small enums it's probably more efficient to step through the list.
- 对于小型枚举,单步执行列表可能更有效。
Incidentally:
顺便:
- In this situation I would have gone with convention and used name() since it's the same as the custom name except for the case (easily fixed.)
- This solution is more useful when what you have to look up is completely different to the name() value.
- 在这种情况下,我会使用约定并使用 name() 因为它与自定义名称相同,但大小写除外(易于修复。)
- 当您必须查找的内容与 name() 值完全不同时,此解决方案更有用。
回答by KLE
I agree with your desire to have no exception created. It's good for performance (as an exception is worth a thousand instructions, for building the stack trace), and it's logical when you say that it is often the case that it is not found (therefore, it is not an exceptionalcondition).
我同意你希望没有例外的愿望。这对性能有好处(因为异常值一千条指令,用于构建堆栈跟踪),并且当您说通常找不到它的情况时这是合乎逻辑的(因此,这不是异常情况)。
I think the for loop
you mention is correct, if you have only a few enum values. It will probably have the best performance of all. But I understand you don't want it.
for loop
如果您只有几个枚举值,我认为您提到的是正确的。它可能拥有最好的性能。但我明白你不想要它。
You could build a Map to find your enum values, that would avoid the exception and return the appropriate enum at the same time.
您可以构建一个 Map 来查找您的枚举值,这将避免异常并同时返回适当的枚举。
Update : Trejkaz already posted the code that does this.
更新: Trejkaz 已经发布了执行此操作的代码。
Also note that sometimes, instead of returning null
as the return type when no instance matches, some enum have a dedicated instance for that (call it EMPTY or NOT_FOUND for example). The advantage is that all calling code doesn't have to deal with nulls, and risk no NullPointerException
. If needed, there can a boolean method that says isFound()
(returns true except for that instance). And codes that would really need to differenciate that values from others still can, while the ones that don't care just pass the instance around without knowledge of this special case.
另请注意,有时,null
当没有实例匹配时,不是作为返回类型返回,而是某些枚举具有专用实例(例如,将其称为 EMPTY 或 NOT_FOUND)。优点是所有调用代码都不必处理空值,并且没有风险NullPointerException
。如果需要,可以有一个布尔方法表示isFound()
(除该实例外返回真)。真正需要区分值与其他值的代码仍然可以,而那些不关心的代码只是在不了解这种特殊情况的情况下传递实例。
回答by Rap
I'll be the contrarian here ... I think your first impulse (to throw an exception) is the right thing to do.
我将成为这里的逆势投资者……我认为您的第一个冲动(抛出异常)是正确的做法。
If you're checking within the business logic rather than the UI, there won't be any feedback at that level to the user. (If you're not checking in the UI, we have other problems). Therefore, the proper way to handle it is by throwing an exception.
如果您在业务逻辑而不是 UI 中进行检查,则不会在该级别向用户提供任何反馈。(如果您没有检查 UI,我们还有其他问题)。因此,处理它的正确方法是抛出异常。
Of course that doesn't mean you have to have the exception bubble up to the UI level thus short-circuiting the rest of your logic. What I usually do it put the enum assignment in its own little try-catch and handle the exception by reassigning or whatever other elegant solution you've devised.
当然,这并不意味着您必须将异常冒泡到 UI 级别,从而使其余逻辑短路。我通常做的是将枚举分配放在自己的小 try-catch 中,并通过重新分配或您设计的任何其他优雅解决方案来处理异常。
In short ... you were on the money with your first thought. Go with it. Just change your exception handling a little different.
简而言之......你的第一个想法就是赚钱。随它去。只是改变你的异常处理有点不同。
回答by Tom Jefferys
Perhaps you shouldn't be using an Enum at all? If you're regularly having to deal with values that aren't defined in your Enum, perhaps you should be using something like a HashMap<String,Fruit> You can then use containsKey(), to find out if a particular key exist.
也许您根本不应该使用 Enum ?如果您经常需要处理 Enum 中未定义的值,也许您应该使用 HashMap<String,Fruit> 之类的东西。然后您可以使用 containsKey() 来确定特定键是否存在。
回答by JRL
Just to mention another possibility that'll let your calling code not have to worry about exceptions or conditional checks is to always return a Fruit. If the string is not found, return Fruit.UNKNOWN, for example.
只是提到另一种让您的调用代码不必担心异常或条件检查的可能性是始终返回 Fruit。例如,如果未找到该字符串,则返回 Fruit.UNKNOWN。
Example:
例子:
public enum Fruit {
public Fruit getValueOf(String name) {
for (Fruit fruit : Fruit.values()) {
if (fruit.fruitname.equals(name))
return fruit;
}
}
return UNKNOWN;
}
...
}
回答by dogbane
This is how you can do it using EnumSet.allOf to populate a map:
这是使用 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);
}
}
回答by kman
There is an apache commons lang EnumUtils.isValidEnum(). Unfortunately, Under the hood, this is using try/catch logic and returning boolean, but at least your code looks clean:
有一个 apache commons lang EnumUtils.isValidEnum()。不幸的是,在幕后,这是使用 try/catch 逻辑并返回布尔值,但至少您的代码看起来很干净:
if(EnumUtils.isValidEnum(Fruit.class, fruitname)) { ....
You will need to use the latest commons-lang3 library as commons-lang 2.x does not have this function.
您需要使用最新的 commons-lang3 库,因为 commons-lang 2.x 没有这个功能。
回答by Yeison
This is my solution. I created a set so that you don't have to specify a constructor. This also has the added benefit that the value being looked up has to match the case of the enum.
这是我的解决方案。我创建了一个集合,这样您就不必指定构造函数。这还有一个额外的好处,即正在查找的值必须与枚举的大小写相匹配。
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);
}
}
回答by charlb
In java8 you can do it like this
在java8中你可以这样做
public static boolean isValidFruit(final String fruit) {
return Arrays.stream(Fruit.values())
.map(Fruit::name)
.collect(Collectors.toSet())
.contains(fruit);
}