一、分析
每個列舉都是java.lang.Enum的子類,都可以訪問Enum類提供的方法,比如hashCode、name、valueOf等,其中valueOf方法會把一個String型別的名稱轉變成列舉項,也就是在列舉項中查詢字面值和該引數相等的列舉項。
我們來深入分析一下該valueOf方法的原始碼:
public static <T extends Enum<T>> T valueof(Class<T> enumType,String name){
//通過反射,從常量列表中查詢
T result = enmuType.enumConstantDirector().get(name);
if(result != null)
return result;
if(name == null)
throw new NullPointerException("Name is null");
//最後排除無效引數異常
throw new IllegalArgumentException("No enum const" + enumType + "." + name);
}
valudOf方法通過反射從列舉類的常量宣告中查詢,若找到就直接返回,若找不到則丟擲無效引數異常。valueOf的本意是保護編碼的列舉安全性,使其不產生空列舉物件,簡化列舉操作,但是卻又引入了一個我們無法避免的IllegalArgumentException異常。
二、場景
我們來看如下程式碼:
public static void main(String[] args){
//注意summer是小寫
List<String> params = Arrays.asList("Spring","summer");
for(String name:params){
//查詢字面值與name相同的列舉項
Season s = Season.valueOf(name);
if(s != null){
//有列舉項時
System.out.println(s);
}else{
//沒有列舉項
System.out.println("沒有相關列舉項");
}
}
}
summer無法轉換Season列舉,根據上面的分析,就會丟擲IllegalArgumentException異常,一旦丟擲異常,後續的程式碼就不執行了!!!
這與我們的習慣很不一致,例如我們從一個List中查詢一個元素,即使不存在也不會報錯,頂多返回indexOf方法返回-1。
三、建議
1.使用try-catch捕捉異常
try{
Season s = Season.valueOf(name);
//有該列舉項時處理
System.out.println("s");
}catch(Exception e){
System.out.println("無相關列舉項");
}
2.擴充套件列舉類
由於Enum類定義的方法都是final型別的,所以不希望被覆寫,我們可以通過增加一個contains方法來判斷是否包含指定的列舉項,然後在繼續轉換,程式碼如下:
enum Season{
Spring,Summer,Autumn,Winter;
//是否包含列舉項
public static boolean contains(String name){
//所有的列舉值
Season[] season = values();
//遍歷查詢
for(Season s : season){
if(s.name().equals(name)){
return true;
}
}
return false;
}
}