Java Enum valueOf效率

您认为哪个更有效率?

使用’WeekDay’只是一个例子:

public enum WeekDay { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY; } 

循环并首先validation日期字符串:

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

或者因为在99.99%的情况下,一天是正确的:

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

更新

为了澄清,输入字符串将来自客户端应用程序,而不是用户。 换句话说,在这个例子中收到非工作日将是一个错误。

我知道这是一个老post,但我相信以下结果仍然很有趣。 我运行10000000次测试,使用JDK 1.8在enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST}查找元素。 下表显示了简单循环和valueOf()所需的时间。

文本循环值比率
 ------------------------------
 “第一”121 65 186%
 “最后”188 57 330%
 “foo”155 8958 1.7%

结论 – 如果我期望值不匹配枚举,我不会使用valueOf()

第二种方法的性能问题是什么? 抓住这样的例外几乎没有任何成本。 从设计角度来看,使用常规控制流程的exception通常是一个坏主意,这是性能考虑的日子早已不复存在。 在调试器中,使用exception作为重要的控制操作会使事情减慢大约10倍。但这会被JIT优化,并且在生产中没有可测量的影响。

这些数字是基于我对zxing项目进行评估的经验,该项目使用了各种流量控制的例外情况。 当我第一次看到它时,我感到震惊。 我仍然认为这不是最好的设计,但我做了相当多的测试,可以肯定地说它对性能没有实际影响。 这是一种在整个地方使用exception进行流量控制的算法。 您的情况,即exception只会在非常特殊的情况下被抛出,这是一个非问题。

编辑:我的回答中有一两个问题,我想确保我对我所说的内容非常清楚:我不认为对正常控制流使用exception是个好主意。 仅仅因为性能不是不使用exception的好方法,这并不意味着没有其他完全正确的原因(例如可读性,可测试性,可扩展性)。 在OP的情况下,绝对需要使用exception,并且绝对不会导致任何类型的性能问题。

正如已经评论过的那样,您必须进行剖析才能确定。 即使在您自己的解析方法中,您也可以通过在解析列表时返回枚举来加快速度。

 private WeekDay getValidWeekDay(String day) { for (WeekDay weekDay : WeekDay.values()) { if(weekDay.toString().equals(day)) return weekDay; } return null; } 

除非这是一个时间关键的应用程序,否则在任何一种情况下我都不会担心,只需采用最易读的方法。 我认为这将使用WeekDay.valueOf()方法。

如果您不想处理exception,那么在枚举中创建一个值的Map,并从查找中有效地执行valueOf(),如果找不到则返回null。

 public enum WeekDay { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY; private static Map valueMap; public static WeekDay getValue(String possibleName) { if (valueMap == null) { valueMap = new HashMap(); for(WeedDay day: values()) valueMap.put(day.toString(), day); } return valueMap.get(possibleName); } } 

这实际上是valueOf()方法正在执行的操作,除非它在找不到时抛出IllegalArgumentException。 这种方法只会返回null,因此不会生成堆栈跟踪。

如果您的问题确实是关于7项目中搜索的效率,那么您已经浪费了太多时间。 即使是最快的搜索算法也会产生零或负的好处,直到N> 15左右,而不是O(1)。

将有效字符串存储在HashSet ,并根据Set.contains(...)确定字符串是否为有效日期。

该集合可以是一个static final Set ,并且您可以包装一个不可修改的好的度量:

 private static final Map WEEKDAY_STRINGS; static { HashSet set = new HashSet(); for (WeekDay d : WeekDay.values()) { set.add(d.toString()); } WEEKDAY_STRINGS = Collections.unmodifiableSet(set); } 

循环不执行任何调用valueof的操作,它们具有相同的function:检查字符串是否有效枚举。 您认为从第一个选项中获得了什么?

第二种选择是最好的:

  try { WeekDay weekDay = WeekDay.valueOf(day); // might throw exception ... } catch (IllegalArgumentException e) { throw new InvalidWeekDayException(day); } 

或者,您可以在类首次加载时查看枚举值(请参阅静态修饰符)并使用get()进行validation,如下所示:

 private String dayName; private static final Map lookup = new HashMap(); static{ for (Weekday day: values()){ lookup.put(day.dayName, d); } } public static Weekday get(String _name){ return lookup.get(_name); } 

如果您需要更多详细信息,请告诉我们