提高你的Java程式碼質量吧:使用valueof前必須進行校驗

weixin_34037977發表於2013-09-13

一、分析 

每個列舉都是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; 
    } 
} 


 

 

相關文章