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