уникальный токен имени enum, определенный во время инициализации класса - PullRequest
4 голосов
/ 03 февраля 2012

Я определил следующее перечисление в 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)

Ответы [ 2 ]

4 голосов
/ 03 февраля 2012

Вы можете обойти это следующим образом:

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 статическим полем статического внутреннего класса, вы гарантируете, что он будет инициализирован до создания первого перечисления.

Кроме того, я позволил себе изменить / исправить несколько вещей в вашем коде:

  • Используйте Set вместо List: значения уникальны
  • Использование split(): в java
  • Remove else: после return или throws, else всегда является избыточным, потому что выполнение блока прекращается этими ключевыми словами (нет «else» для обработки)


Кроме того, этот метод также отлично подходит для ленивой инициализации из синглетонов :

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

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

Поле INSTANCE создается только при первом вызове метода getInstance()!

Смотри, мама! Ленивая инициализация без блокировок, без нулевых проверок, без синхронизации любого типа и 100% пуленепробиваемая! (Несмотря на то, что десериализация объекта взломана)

Это волшебство:)

1 голос
/ 03 февраля 2012

Я сделал нечто подобное, и мне помогло следующее:

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


}
...