2009-06-29 98 views
0

我會經常需要從串碼轉換成其Enum類型。 請參閱下面的代碼片段。我認爲這是非常低效的。如何改進 方法deref以便:如何改進這種枚舉類型?

  • 這將是線程安全的。
  • 這是更快。

代碼:

public enum SigninErrorCodes 
{ 
    InvalidUser("a0"), InvalidPassword("b5"), NoServerResponse("s2"); 

    SigninErrorCodes(String code) { _code = code; } 

    public String code() { return _code; } 

    public static SigninErrorCodes deref(String code) 
    { 
     SigninErrorCodes[] verbs = values(); 
     Map<String, SigninErrorCodes> m = new HashMap<String,SigninErrorCodes>(3); 
     for(int i=0; i<verbs.length; i++) 
     m.put(verbs[i].code(), verbs[i]); 

     return m.get(code); 
    } 

    private final String _code; 
} 

回答

1

如果可能的值的列表真的就是這麼小,然後手工編寫的方法。與單純的3個字符串比較相比,哈希表的性能優勢不會受到影響。

但是,如果像我懷疑,值的數量要大於你寫了那麼一個地圖是有道理的,在這種情況下創建枚舉時,你應該緩存地圖。

public enum SigninErrorCodes { 
    InvalidUser("a0"), InvalidPassword("b5"), NoServerResponse("s2"); 

    private final String _code; 
    SigninErrorCodes(String code) { _code = code; } 
    public String code() { return _code; } 

    private static final Map<String, SigninErrorCodes> m; 

    static { 
    SigninErrorCodes[] verbs = values(); 
    m = new HashMap<String,SigninErrorCodes>(verbs.length * 2); 
    for(int i=0; i<verbs.length; i++) 
     m.put(verbs[i].code(), verbs[i]); 
    } 


    public static SigninErrorCodes deref(String code) { 
    return m.get(code); 
    } 
} 

請注意,給出散列圖的最佳大小不是元素的數量,而是大約兩倍。較低的數字會導致關鍵衝突。

+0

馬庫斯,這很有趣。你能否指出我的一個消息來源說HashMaps應該被初始化爲其預期密鑰的兩倍? – Yishai 2009-06-29 03:07:24

2

枚舉有一個稱爲[的valueOf] [1]來處理這個靜態方法。你會這樣做:

public static SigninErrorCodes deref(String code){ 
     try { 
      return Enum.valueOf(SignInErrorCodes.class, code); 
     } catch (IllegalArgumentException e) { 
      return null; 
     } catch (NullPointerException e) { 
      return null; 
     } 
} 

請注意,這裏的錯誤處理嘗試模仿與原始方法相同的結果。這可能不是事實,你希望如何處理無效代碼,或者你可能會假設會有在運行時不存在無效代碼,那麼你只會讓例外傳播。

上述適用,如果你可以根據代碼命名枚舉(東西都是非常需要在這種情況下,它似乎)。

如果由於某種原因無法實現,那麼您可以很簡單地使用Hashtable(同步化)作爲您的映射實現,並將其保存在靜態字段中,並將其填充到枚舉的構造函數中。把(_code,this.getClass());)。

如果過度同步化太多的性能,明智的,然後再看看存儲一個ThreadLocal地圖。

[1]:http://java.sun.com/javase/6/docs/api/java/lang/Enum.html#valueOf(java.lang.Class,java.lang.String中)

+1

您也可以只調用的valueOf靜態成員:SigninErrorCodes.valueOf(代碼);但是,根據計劃,每個未接電話的例外成本可能很高。 – 2009-06-29 03:05:16

1

一兩件事,這將使它更快保持地圖在一個靜態變量,這樣你就不必每次重新計算它;不知道線程安全的部分。

public enum SigninErrorCodes { 
    InvalidUser("a0"), InvalidPassword("b5"), NoServerResponse("s2"); 

    private static Map<String, SigninErrorCodes> m = new HashMap<String,SigninErrorCodes>(3); 

    SigninErrorCodes(String code) { _code = code; m.put(code, this); } 

    public String code() { return _code; } 

    public static SigninErrorCodes deref(String code) 
    { 
     return m.get(code); 
    } 
} 

如果代碼串是有效的標識符,你可以使用它們作爲枚舉值直接:

public enum SigninErrorCodes { a0, b5, s2; } 

// and then when you need to look it up, use: 
SigninErrorCodes.valueOf("b5");