我在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)
您可以按照以下方式解决此问题:
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()
:java中String
没有这样的方法tokenize()
- 删除
else
:在return
或throws
之后,else
总是多余的,因为块的执行被这些关键字暂停(没有"其他"可处理)
顺便说一句,这种技术对于单态的惰性初始化也很好:
public class MyLazySingleton() {
private static class InstanceHolder {
static MyLazySingleton INSTANCE = new MyLazySingleton();
}
public static MyLazySingleton getInstance() {
return InstanceHolder.INSTANCE;
}
}
INSTANCE
字段仅在首次调用getInstance()
方法时构造!
看妈妈!懒惰的初始化没有锁,没有空检查,没有任何类型的同步和100%防弹!(尽管存在对象反序列化黑客)
这很神奇:)
我也做过类似的事情,以下对我有效:
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);
}
}