[英]Java Enum.valueOf() efficiency when value does not exist
您認為哪種效率更高?
使用'WeekDay'只是一個例子:
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);
}
}
更新 :
為了澄清,輸入字符串將來自客戶端應用程序,而不是用戶。 換句話說,在這個例子中收到非工作日會是一個錯誤。
第二種方法的性能問題是什么? 抓住這樣的例外幾乎沒有任何成本。 從設計角度來看,使用異常進行正常控制流通常是一個壞主意,這是性能考慮的日子早已不復存在。 在調試器中,使用異常作為重要的控制操作會使事情減慢大約10倍。但這會被JIT優化,並且在生產中沒有可測量的影響。
這些數字是基於我對zxing項目進行評估的經驗,該項目使用了各種流量控制的例外情況。 當我第一次看到它時,我感到震驚。 我仍然認為這不是最好的設計,但我做了相當多的測試,可以肯定地說它對性能沒有實際影響。 這是一種在整個地方使用異常進行流量控制的算法。 您的情況,即異常只會在非常特殊的情況下被拋出,這是一個非問題。
編輯:我的答案中有一兩個下注,我想確保我對我所說的內容非常清楚:我不認為對正常控制流使用異常是個好主意。 僅僅因為性能不是不使用異常的好方法,這並不意味着沒有其他完全正確的原因(例如可讀性,可測試性,可擴展性)。 在OP的情況下,絕對要求使用異常,並且肯定不會導致任何類型的性能問題。
我知道這是一個老帖子,但我相信以下結果仍然很有趣。 我運行了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%
結論 - 如果我期望值不匹配枚舉,我不會使用valueOf()
。
正如已經評論過的那樣,您必須進行剖析才能確定。 即使在您自己的解析方法中,您也可以通過在解析列表時返回枚舉來加快速度。
private WeekDay getValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return weekDay;
}
return null;
}
除非這是一個時間關鍵的應用程序,否則我不會在任何一種情況下擔心它,只需采用最易讀的方法。 我認為這將使用WeekDay.valueOf()方法。
如果您不想處理異常,那么在枚舉中創建一個值的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);
}
}
這實際上是valueOf()方法正在做的事情,除非它在找不到時拋出IllegalArgumentException。 這種方法只會返回null,因此不會生成堆棧跟蹤。
如果您的問題確實是關於7項目中搜索的效率,那么您已經浪費了太多時間。 即使是最快的搜索算法也會產生零或負的好處,直到N> 15左右,而不是O(1)。
將有效字符串存儲在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);
}
循環不執行任何調用valueof的操作,它們具有相同的功能:檢查字符串是否有效枚舉。 您認為從第一個選項中獲得了什么?
第二種選擇是最好的:
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day);
}
或者,您可以在類首次加載時查看枚舉值(請參閱靜態修飾符)並使用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);
}
如果您需要更多詳細信息,請告訴我們
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.