2011-08-23 140 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)。