2011-08-23 169 views
7

您认为哪种效率更高?Java枚举值效率

使用“工作日”仅仅是一个例子:

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

循环并确认日线第一:

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

更新

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

+7

这可能听起来像是一个荒谬的答案,但我认为当我将其描述为最有效时,它运行速度最快。 –

+0

字符串是来自用户输入的内容,还是全部来自内部? – DHall

+0

我想用它来代替,如果你真的在做一个星期几的枚举:http://joda-time.sourceforge.net/field.html#dayOfWeek – NimChimpsky

回答

4

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

 
text  loop valueOf ratio 
------------------------------ 
"FIRST" 121 65  186% 
"LAST" 188 57  330% 
"foo" 155 8958  1.7% 

结论 - 如果期望值与enum不匹配,我不会使用valueOf()

+0

您的测试是否专注于使用异常的效率命中?或者是valueOf()方法中某些实现细节的差异b/c?你是否在运行JIT的正常运行的JVM(即不是在调试模式下)运行它?你是否在启动计时器之前通过一系列迭代来加热JIT?当我使用zxing进行测试时,我看到了在调试模式下运行测试时显示的差异类型 - 但是一旦调试器出现问题,性能几乎相同。 –

+0

嘿@凯文。有许多参数会影响表中的具体数字。我只是对_my environment_(Oracle JVM 1.6 + 64位Win7 + Debug模式)中的“异常成本”感到好奇。我对结果感到非常惊讶,因此决定发布它。根据我的C++经验,我预计最坏情况下的比例为10-20%。 – aknopov

2

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

设定可以是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); 
} 
+1

这是过度复杂的问题恕我直言 – NimChimpsky

2

循环将不会做任何调用的valueOf不,它们具有相同的功能:检查不管你的字符串是否为有效的枚举。你认为你从第一种选择中获得了什么?

第二个选择是最好的:

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

我想它的全部归结为常见的无效日子。如果有50%的天是无效的,那么有些人会认为抛出异常是非常低效的。但是,如果它只有罕见的客户端应用程序错误,那么这绝对是一条可行的路。 – toolkit

2

或者你可以创建枚举值的查找你的枚举内上课的时候第一次加载(见static修饰符),并使用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); 
} 

让我知道,如果你需要更多的细节

5

由于进行了报道,你将不得不剖析,找出肯定的。即使在你自己的解析方法中,当你解析列表时,你可以通过返回枚举来加快速度。

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

除非这是一个应用程序的时间关键部分,否则我不会担心这种情况,而只是采取最可读的方法。我认为这将使用WeekDay.valueOf()方法。

如果您不想处理异常,请在枚举中创建一个您的值的映射,并从查找中有效地执行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); 

    } 
} 

这实际上是什么的valueOf()方法就是这么做的,除了它抛出抛出:IllegalArgumentException时候没有找到它。这种方法只会返回null,因此不会生成堆栈跟踪。

8

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

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

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

+1

感谢Kevin的建议。 – toolkit

3

如果你的问题真的是关于在7个项目中搜索的效率,你已经浪费了太多的时间。即使是最快的搜索算法,直到N> 15左右才会产生零或负面收益,而不是O(1)。