1、異常分類
從產生源頭來看,Java語言中的異常可以分為兩類:
JVM拋出的異常。比如:訪問null引用會引發NullPointerException;0作為除數,如9/0,JVM會拋出ArithmeticException;內存消耗完,申請分配失敗,JVM會拋出OutOfMemoryError。
注意:這些JVM的異常也可以在java代碼中顯式拋出(盡管我們很少這么做,基本也沒有必要),如下例子中的代碼可以正常編譯。
public class Test {
public static void main(String []args){
String s = null;
if (s == null) {
throw new NullPointerException("Exception: s should not be null");
}
throw new OutOfMemoryError();
}
}
除了JVM的異常,其他異常都是程序引起的,是程序中顯式通過throw語句拋出的。
比如,在Long.parseLong(String s, int radix)的源碼中包含如下代碼:
if (s == null) {
throw new NumberFormatException("null");
}
也就是說,方法會拋出NumberFormatException異常。
一般情況下,jvm異常是由jvm拋出的,不會被開發者顯式拋出。當然,也可以在程序中通過throw語句顯式拋出jvm異常。如下:
if (s == null) {
throw new NullPointerException(“s can not be null”);
}
所有的jvm異常都是unchecked,而程序中的異常則unchecked和checked都有。
2、異常類的繼承層次
Java語言中的類繼承層次如下圖:
Java異常層次
Throwable有兩個子類Exception和Error。其中:
Exception是和應用相關的,NullPointerException出現在當試圖訪問空對象的時候,ClassCastException出現在試圖轉換不兼容的類型時。可以通過try catch語句捕獲Exception之后處理,可以讓程序恢復運行。
Error是和應用運行的環境相關的,比如OutOfMemoryError出現在jvm內存耗盡的時候、StackOverflowError出現在棧溢出的時候。正因為如此,程序基本不可能在Error發生時恢復,所以,Error不能被try catch語句處理。
從這個圖中可以看出,類也分為Checked異常和Unchecked異常。
Checked異常是java編譯器強制處理的異常,必須通過try catch語句捕獲,或者通過throws語句拋出。如果顯式不處理,就會編譯報錯。比如網絡連接失敗的時候,會拋出IOException,程序應該提前預料并對這個異常做出恰當的處理,比如在網絡中斷時重新傳輸文件,這樣程序才不會因為異常終止運行,崩潰掛掉。
Unchecked異常通常是開發者代碼邏輯錯誤造成的:如NullPointerException(通常在程序設計時通過檢查引用是否為空避免);如一些是java.lang.Error的子類,在任何一個實例對象創建的時候都有可能發生OutOfMemoryError(但是,我們不可能在每一個創建對象實例的地方都用try catch捕獲這個異常,因為這個異常是unchecked,在實際編程中也無需這么做)。通常來說,unchecked異常是無法預料,編譯器無法檢測的異常。
3、checked和unchecked異常
自定義的異常是checked,還是unchecked取決于繼承的父類是checked異常,還是unchecked異常。
try catch塊中catch的checked異常,必須在try塊中有出現這種異常的可能性,不然編譯不通過。但是,Throwable和Exception這兩個類有些特殊,盡管他們是checked異常,不過,即使在try塊中沒有出現該異常的可能性,依然可以捕獲它們。因為他們都有unchecked異常子類(如RuntimeException),編譯器不檢查unchecked異常,也就允許這樣捕獲unchecked異常。
參考資料