我已经实现了一个小助手类,它为枚举的 valueOf 方法提供了一个简单的故障安全实现。这意味着如果找不到该值,它将返回 null 而不是异常。
这是代码:
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.io.Serializable;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <p>
* This permits to easily implement a failsafe implementation of the enums's valueOf method
* </p>
*
* <p>
* Basic usage exemple on an enum class called MyEnum:
* FailSafeValueOf.get(MyEnum.class).valueOf("EnumName");
* </p>
*
* @author Sebastien Lorber <i>(lorber.sebastien@gmail.com)</i>
*/
public class FailSafeValueOf<T extends Enum<T>> implements Serializable {
/**
* This will cache a FailSafeValueOf for each enum so that we do not need to recompute a map each time
*/
private static final Map< Class<? extends Enum<?>> , FailSafeValueOf<? extends Enum<?>> > CACHE = Maps.newHashMap();
private final Map<String,T> nameToEnumMap;
private FailSafeValueOf(Class<T> enumClass) {
Map<String,T> map = Maps.newHashMap();
for ( T value : EnumSet.allOf(enumClass)) {
map.put( value.name() , value);
}
this.nameToEnumMap = ImmutableMap.copyOf(map);
}
/**
* Returns the value of the given enum element
* If the element is not found, null will be returned, and no exception will be thrown
* @param enumName
* @return
*/
public T valueOf(String enumName) {
return nameToEnumMap.get(enumName);
}
/**
* Get a failsafe value of implementation for a given enum
* @param enumClass
* @param <U>
* @return
*/
public static <U extends Enum<U>> FailSafeValueOf<U> get(Class<U> enumClass) {
FailSafeValueOf<U> fsvo = (FailSafeValueOf<U>)CACHE.get(enumClass);
if ( fsvo == null ) {
synchronized (FailSafeValueOf.class) {
fsvo = (FailSafeValueOf<U>)CACHE.get(enumClass);
if ( fsvo == null ) {
fsvo = new FailSafeValueOf<U>(enumClass);
CACHE.put(enumClass,fsvo);
}
}
}
return fsvo;
}
}
因为我不希望在每次访问时创建一个新的 FailSafeValueOf 的(小)开销,所以我制作了一个缓存,为每个已经访问过的枚举保存一个已经构建的 FailSafeValueOf 实例。
我不习惯处理并发。在这种情况下,并发访问可能不是大问题,因为 FailSafeValueOf 是不可变的,并且同一枚举的 get 方法可以返回 2 个不同的 FailSafeValueOf 实例。但是我想知道我的线程安全实现是否可行,以及它是否真的是线程安全的?(主要用于学习目的)
我不想让我的方法同步,因为一段时间后,所有的FailSafeValueOf都在缓存中创建,不需要禁止并发线程进入get方法。
所以我所做的是首先检查是否有缓存未命中,然后创建一个自动同步的块:再次检查缓存并最终创建实例。它是线程安全的并且是满足这种需求的方法吗?
顺便说一句,枚举通常具有少量值。在这种情况下,HashMap 是一个合适的结构吗?迭代 EnumSet 并获得适当的值是否比使用缓存更快?
编辑:
请注意,我的课程不是很有用,因为 Guava 团队已经关联了一个 Enums.getIfPresent() 方法,它返回一个 Optional