值不存在时的 Java Enum.valueOf() 效率
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7164906/
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
Java Enum.valueOf() efficiency when value does not exist
提问by toolkit
Which would you consider more efficient?
你认为哪个更有效率?
The use of 'WeekDay' is just an example:
'WeekDay' 的使用只是一个例子:
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
}
Loop through and verify day string first:
首先循环并验证日期字符串:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
if (isValidWeekDay(day)) {
WeekDay weekDay = WeekDay.valueOf(day); // won't throw exception
...
} else {
throw new InvalidWeekDayException(day); // subclass of RuntimeException
}
}
private boolean isValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return true;
}
return false;
}
Or since in 99.99% of cases, day will be correct:
或者因为在 99.99% 的情况下,day 将是正确的:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day, e);
}
}
Update:
更新:
To clarify, the input string will come from a client application, rather than a user. So in other words, it would be a bug to recieve a non workday in this example.
澄清一下,输入字符串将来自客户端应用程序,而不是用户。因此,换句话说,在此示例中收到非工作日将是一个错误。
采纳答案by aknopov
I know its an old post, but I believe following result will be still interesting. I run 10000000 tests to find an element in enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST}
using JDK 1.8. The table below shows time required by simple loop and valueOf()
.
我知道这是一个旧帖子,但我相信下面的结果仍然很有趣。我运行了 10000000 次测试以找到enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST}
使用 JDK 1.8的元素。下表显示了简单循环和 所需的时间valueOf()
。
text loop valueOf ratio ------------------------------ "FIRST" 121 65 186% "LAST" 188 57 330% "foo" 155 8958 1.7%
Conclusion - I wouldn't use valueOf()
if I expect values not matching enum.
结论 -valueOf()
如果我期望值与枚举不匹配,我不会使用。
回答by Kevin Day
What is the performance concern about the 2nd approach? Catching an exception like that costs almost nothing. Using exceptions for normal control flow is generally a bad idea from a design perspective, the days where this was a performance consideration are long gone. In a debugger, using exceptions as significant control operations will slow things down by a factor of about 10. But this gets optimized by the JIT and there is no measurable impact in production.
第二种方法的性能问题是什么?捕获这样的异常几乎不需要任何费用。从设计的角度来看,对正常控制流使用异常通常是一个坏主意,将其作为性能考虑的日子早已一去不复返了。在调试器中,使用异常作为重要的控制操作会减慢大约 10 倍的速度。但这会被 JIT 优化并且对生产没有可测量的影响。
These numbers are based on experience with an evaluation I did of the zxing project, which uses exceptions for all sorts of flow control. When I first saw it, I was horrified. I still think it's not the best design, but I did quite a bit of testing and can say with a good bit of confidence that it had no real impact on performance. And this is an algorithm that was using exceptions all over the place for flow control. Your situation, where the exception will only get thrown in highly exceptional circumstances, is a non issue.
这些数字基于我对 zxing 项目所做的评估的经验,该项目使用异常进行各种流量控制。当我第一次看到它时,我被吓坏了。我仍然认为这不是最好的设计,但我做了相当多的测试,可以很有信心地说它对性能没有真正的影响。这是一种在所有地方都使用异常进行流量控制的算法。您的情况,只有在非常特殊的情况下才会抛出异常,这不是问题。
Edit: I've had a downvote or two on my answer, and I want to make sure that I'm super clear on what I'm saying: I do not think that it's a good idea to use exceptions for normal control flow. Just because performance is not a good argument for not using exceptions this way doesn't mean that there aren't other, perfectly valid reasons (such as readability, testability, extendability). In the case of the OP, the use of an exception is absolutely called for, and definitely wouldn't cause any sort of performance issue.
编辑:我对我的回答有一两个反对意见,我想确保我对我在说什么非常清楚:我认为对正常控制流使用异常不是一个好主意。仅仅因为性能不是不以这种方式使用异常的好理由,并不意味着没有其他完全有效的理由(例如可读性、可测试性、可扩展性)。在 OP 的情况下,绝对需要使用异常,并且绝对不会导致任何类型的性能问题。
回答by Robin
As has been commented, you will have to profile to find out for sure. Even in your own parsing approach, you can make it faster by returning the enum when you parse the list.
正如所评论的那样,您必须进行概要分析才能确定。即使在您自己的解析方法中,您也可以通过在解析列表时返回枚举来加快速度。
private WeekDay getValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return weekDay;
}
return null;
}
Unless this is a time critical piece of an application, I wouldn't worry about it in either case and simply take the most readable approach. I think that would be using the WeekDay.valueOf() method.
除非这是应用程序的时间关键部分,否则我不会在任何一种情况下担心它,只是采用最易读的方法。我认为这将使用 WeekDay.valueOf() 方法。
If you would rather not have to deal with exceptions, then create a Map of your values within the enum and effectively do the equivalent of valueOf() from a lookup which returns null if it is not found.
如果您不想处理异常,则在枚举中创建您的值的 Map 并有效地从查找中执行 valueOf() 的等效操作,如果未找到则返回 null。
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
private static Map<String, WeekDay> valueMap;
public static WeekDay getValue(String possibleName)
{
if (valueMap == null)
{
valueMap = new HashMap<String, WeekDay>();
for(WeedDay day: values())
valueMap.put(day.toString(), day);
}
return valueMap.get(possibleName);
}
}
This is effectively what the valueOf() method is doing anyway, except it throws the IllegalArgumentException when it is not found. This approach will simply return null, thus not generating the stacktrace.
无论如何,这实际上是 valueOf() 方法正在执行的操作,除非它在未找到时抛出 IllegalArgumentException。这种方法将简单地返回 null,因此不会生成堆栈跟踪。
回答by user207421
If your question is really about the efficiency of searching among 7 item you have already wasted too much time on it. Even the fastest search algorithms yield zero or negative benefits until N > 15 or so, other than the O(1) one.
如果您的问题真的是关于在 7 个项目中搜索的效率,那么您已经浪费了太多时间。即使是最快的搜索算法也会产生零或负收益,直到 N > 15 左右,而不是 O(1) 一。
回答by Dilum Ranatunga
Store the valid strings in a HashSet
, and decide whether a string is a valid day or not based on Set.contains(...)
.
将有效字符串存储在 a 中HashSet
,并根据 确定字符串是否为有效日期Set.contains(...)
。
The set can be a static final Set
, and you can wrap in an unmodifiable for good measure:
该集合可以是 a static final Set
,并且您可以将其包装在一个不可修改的中以进行良好的衡量:
private static final Map<String> WEEKDAY_STRINGS;
static {
HashSet<String> set = new HashSet();
for (WeekDay d : WeekDay.values()) {
set.add(d.toString());
}
WEEKDAY_STRINGS = Collections.unmodifiableSet(set);
}
回答by NimChimpsky
The loop doesn't do anything that calling valueof doesn't, they have the same functionality : checking whether your string is valid enum. What do you think you gain from the first option ?
循环不会做任何调用 valueof 不会做的事情,它们具有相同的功能:检查您的字符串是否是有效的枚举。您认为您从第一个选项中获得了什么?
The second option is best:
第二种选择是最好的:
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day);
}
回答by Vikram
Or you could create a lookup of enum values inside your enum when the class first loads(see static modifier) and validate using get() as shown below:
或者,您可以在类首次加载时在您的枚举中创建枚举值的查找(请参阅静态修饰符)并使用 get() 进行验证,如下所示:
private String dayName;
private static final Map<String,Weekday> lookup = new HashMap<String, Weekday>();
static{
for (Weekday day: values()){
lookup.put(day.dayName, d);
}
}
public static Weekday get(String _name){
return lookup.get(_name);
}
Let me know if you need more details
如果您需要更多详细信息,请告诉我