A unique enumeration name token defined during class initialization

I defined the following listing in Groovy, although for this question it might be Java code:

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

What I'm trying to do in the constructor is to establish whether the first token in the name of each enum constant is unique, where _ used as a token separator.

However, this code does not work because allSearchTokens not initialized until all constants are created, so I get a NullPointerException here

 allSearchTokens.add(searchToken) 
+4
source share
2 answers

You can get around this as follows:

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

This compiles due to the java specification that all static initializers must be populated before using the class. By making Set a static field of the sttic of an inner class, you guarantee that it will be initialized before the first enumeration is built.

In addition, I allowed to change / fix several things in your code:

  • Use Set , Not List : Values ​​Unique
  • Use split() : there is no such method for String in java
tokenize() for String Delete else : after return or throws , else always redundant because the execution of the block is stopped by these keywords (there is no "else" to process)


As an aside, this method is also great for lazy initialization of singletons :

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

The INSTANCE field is created only the first time the getInstance() method is called!

Look mom! Lazy initialization without locks, without zero checks, without synchronization of any type and 100% bulletproof! (Despite rejecting deserialization of objects)

It `s Magic:)

+4
source

I did something similar and the following worked for me:

 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); } } 
+1
source

Source: https://habr.com/ru/post/1394601/


All Articles