Java 的枚举类型,自带一个valueOf() 方法,来转换字符串到对应的枚举常量,同时,也可以利用枚举类型的 values()[x] 按顺序去取相应的常量。但是对于有自定义数值的枚举,却需要自己处理。例如:
public enum NamedColor {
Red(0xFF0000,"红色"),
Green(0x00FF00,"绿色"),
Blue(0x0000FF,"蓝色");
private int value;
private String name;
NamedColor(int value,String name){
this.value=value;
this.name = name;
}
public int getValue()
{
return this.value;
}
public String getName()
{
return this.name;
}
}
若要把 0xFF0000,或者“红色”转成 NamedColor.Red, 可能需要专门针对这个枚举类写个方法了。
有没有通用的方法呢?本人受 MyBatis Plus的 EnumUtil工具类的启发,写了如下代码,利用Lamda表达式,可以将任意值和任意指定的枚举类型匹配。代码如下:
先声明一个IGetter的函数接口:
@FunctionalInterface
public interface IGetter<T> extends Serializable {
Object apply(T source);
}
然后如下处理:
public static <E extends Enum> E valueOfEnum(@NotNull Class<E> enumClass, @NotNull Object value, @NotNull IGetter<E> ... vGetters )
{
// Step 1. 使用Java 自带的valueOf判断是否匹配枚举常量名
try{
E ec = (E) Enum.valueOf(enumClass,String.valueOf(value)) ;
return ec;
}catch (IllegalArgumentException e){
log.debug(e.getMessage()+",Try to match with value and getters ...");
}
//Step 2 用指定的getter方法,逐个匹配枚举常量的属性值
E[] enumConsts = (E[])enumClass.getEnumConstants();
// Step 2.1 确保以字符串类型给出的数字类型属性值value,也能匹配
BigDecimal nv = null;
try {
nv = new BigDecimal(String.valueOf(value));
}catch( Exception ex ){
log.debug(" Value:'{}' is NOT a valid number.{}",value,ex.getMessage() );
}
//Step 2.2
for ( IGetter<E> getter:vGetters) {
for (E e:enumConsts){
Object ev = getter.apply(e);
if (ev instanceof Number && nv !=null && nv.compareTo(new BigDecimal(String.valueOf(ev))) == 0) {
return e;
}
if (Objects.equals(ev, value)) {
return e;
}
}
}
return null;
}
调用方法:
NamedColor color1 = EnumUtils.valueOfEnum(NamedColor.class,"红色", NamedColor::getName);
NamedColor color2 = EnumUtils.valueOfEnum(NamedColor.class,0xFF00, NamedColor::getValue);
若不知道要匹配的值是什么类型,也可以把可能的getter都放进去:
NamedColor color3 = EnumUtils.valueOfEnum(NamedColor.class,obj, NamedColor::getName,NamedColor::getValue);