这是一个更为通用的解决方案。我在将枚举映射到代码值时使用它。当您的枚举表示一系列离散值,例如映射到数据库表时,它尤其有帮助。请注意,接下来定义的几个类型只需要编写一次,然后就可以在任何枚举上使用。
首先,您需要定义一个接口,您的枚举(或要存储在集合中的POJO)将实现:
public interface Coded<T> {
T getCode();
}
以下代码利用了
Google Guava,但是你也可以执行空值检查而不使用他们的
Optional类:
public final class CodedFinder {
private CodedFinder() {}
public static <V, T extends Enum<T> & Coded<V>> T find(final Class<T> target, final V code) {
final Optional<T> found = findInternal(Arrays.asList(target.getEnumConstants()), code);
if (! found.isPresent()) {
throw new IllegalArgumentException(code.toString() + " is invalid for " + target.getSimpleName());
}
return found.get();
}
private static <V, T extends Coded<V>> Optional<T> findInternal(final Iterable<T> values, final V code) {
return Iterables.tryFind(values, CodedPredicate.of(code));
}
}
上面的方法使用
Class#getEnumConstants 来检索枚举中定义的所有值。实际调用的查找方法不仅可用于枚举,还可用于数组和集合等。
我们需要定义一个
Predicate 来利用
Guava 的查找方法:
public final class CodedPredicate<V, T extends Coded<V>> implements com.google.common.base.Predicate<T> {
private final V value;
private CodedPredicate(final V value) {
this.value = value;
}
public static <V, T extends Coded<V>> CodedPredicate<V, T> of(final V value) {
return new CodedPredicate<V, T>(value);
}
public boolean apply(final T current) {
return value.equals(current.getCode());
}
}
该谓词是通用的,因此您可以使用
Coded<Integer>
或任何其他具有合理
equals()
实现的 POJO。
看起来代码很多,但实际上只定义了三种类型,并且这些类型可以在任意数量的项目之间共享。每当您想要搜索一个值时,它就变得微不足道:
public final class GenderTest {
@Test(groups="unit")
public static void testValid() {
assert CodedFinder.find(Gender.class, "male") == Gender.m;
assert CodedFinder.find(Gender.class, "female") == Gender.f;
}
@Test(groups="unit", expectedExceptions=IllegalArgumentException.class)
public static void testInvalid() {
CodedFinder.find(Gender.class, "foo");
}
public enum Gender implements Coded<String> {
m("male"), f("female");
private final String value;
private Gender(final String option) {
value = option;
}
public String getCode()
{
return value;
}
}
}