2012-02-03 72 views
4

我定義在Groovy以下枚舉,但對這個問題的目的,可能是Java代碼:唯一枚舉名令牌

enum FestivalType { 

    BIG_MUSIC, 
    SMALL_MUSIC, 
    FILM, 
    FOOD_AND_DRINK; 

    private static Set<String> allSearchTokens = new HashSet<String>(); 

    FestivalType() { 
     String searchToken = this.name().tokenize('_').first().toLowerCase(); 

     if (searchToken in allSearchTokens) { 
      throw new RuntimeException("Duplicate search token"); 

     } else { 
      this.searchToken = searchToken; 
      allSearchTokens.add(searchToken); 
     } 
    } 

    final String searchToken; 
} 

我試圖在做構造函數確定每個枚舉常量名稱中的第一個標記是否唯一,其中_用作標記分隔符。

但是,此代碼不起作用,因爲allSearchTokens未初始化直到所有常數初始化,所以我得到了NullPointerException這裏

allSearchTokens.add(searchToken) 

回答

4

可以解決此如下:

public enum FestivalType { 

    BIG_MUSIC, 
    SMALL_MUSIC, 
    FILM, 
    FOOD_AND_DRINK; 

    private static class SetHolder { 
     static Set<String> allSearchTokens = new HashSet<String>(); 
    } 

    final String searchToken; 

    FestivalType() { 
     String searchToken = name().split("_")[0].toLowerCase(); 

     if (SetHolder.allSearchTokens.contains(searchToken)) 
      throw new RuntimeException("Duplicate search token"); 

     this.searchToken = searchToken; 
     SetHolder.allSearchTokens.add(searchToken); 
    } 
} 

由於Java規範的原因編譯,所有靜態初始化必須完成之前該類被使用。通過將Set設置爲sttic內部類的靜態字段,可以保證在構造第一個枚舉之前它將被初始化。

而且,我把改變/在你的代碼固定的幾件事情的自由:

  • 使用Set,而不是List:值是唯一
  • 使用split():沒有這樣的方法tokenize()對於String in java
  • 刪除else:在returnthrows之後,else始終是冗餘的,因爲塊的執行被這些關鍵字阻止(沒有「e倫敦政治經濟學院」來處理)


順便說一句,這種技術也非常適合lazy initializationsingletons的:

public class MyLazySingleton() { 
    private static class InstanceHolder { 
     static MyLazySingleton INSTANCE = new MyLazySingleton(); 
    } 

    public static MyLazySingleton getInstance() { 
     return InstanceHolder.INSTANCE; 
    } 
} 

INSTANCE場只有構建在getInstance()方法首先被調用!

看媽媽!沒有鎖的懶惰初始化,沒有空檢查,沒有任何種類的同步 100%防彈! (儘管有對象反序列化攻擊)

It's magic :)

+0

不錯!我將在未來使用該機制而不是我的機制。 – 2012-02-03 12:27:12

+1

非常聰明,非常感謝。順便說一句,'tokenize()'是Groovy添加到String類的一種方法 – 2012-02-03 12:31:07

+0

我想我記得在有效Java的第2版中使用這種技術進行單例構建 - 必讀 – 2012-02-03 12:42:09

1

我已經做了類似的東西以下爲我工作:

enum MyEnum{ 
    Enum1, Enum2; 

    private static List<String> myList; 

    private static void addToList(MyEnum enum){ 
     if(myList == null){ 
      myList = new ArrayList<String>(); 
     } 

     myList.add(enum.name()); 
    } 

    private MyEnum(){ 
     addToList(this); 
    } 


}