使用枚舉定義常量時,會伴有大量的switch語句判斷,目的是為每個枚舉項解釋其行為,例如這樣一個方法:
public static void doSports(Season season){
switch(season){
case Spring:
System.out.println("春天放風箏");
break;
case Summer:
System.out.println("夏天游泳");
break;
case Autumn:
System.out.println("秋天捉知了");
break;
case Winter:
System.out.println("冬天滑冰");
break;
default:
System.out.println("輸入錯誤!");
break;
}
}
上面的代碼中輸入了一個Season類型的枚舉,然後使用switch進行匹配,目的是輸出每個季節能進行的活動。現在的問題是:這段代碼有沒有問題?
我們先來看它是如何被調用的,因為要傳遞進來的是Season類型,也就是一個實例對象,那當然應該允許為空了,我們就傳遞一個null值進去看看有沒有問題,代碼如下:
public static void main(Stringargs){
doSports(null);
}
似乎會打印出「輸出錯誤!」,因為在switch中沒有匹配到指定值,所以會打印出default的代碼塊,是這樣的嗎?不是,運行後的輸出如下所示:
Exception in thread"main"java.lang.NullPointerException
at Client.doSports(Client.java:9)
at Client.main(Client.java:5)
竟然是空指針異常,第9行也就是switch那一行,怎麼會有空指針呢?這就與枚舉和switch的特性有關了,此問題也是在開發中經常發生的。我們知道,目前Java中的switch語句只能判斷byte、short、char、int類型(JDK 7已經允許使用String類型),這是Java編譯器的限制。問題是為什麼枚舉類型也可以跟在switch後面呢?
很簡單,因為編譯時,編譯器判斷出switch語句後的參數是枚舉類型,然後就會根據枚舉的排序值繼續匹配,也就是說上面的代碼與以下代碼相同:
public static void doSports(Season season){
switch(season.ordinal()){
case Season.Spring.ordinal():
……
case Season.Summer.ordinal():
……
}
}
看明白了吧,switch語句是先計算season變量的排序值,然後與枚舉常量的每個排序值進行對比的。在我們的例子中season變量是null值,無法執行ordinal方法,於是報空指針異常了。
問題清楚了,解決方法也很簡單,在doSports方法中判斷輸入參數是否是null即可。