目錄
Java的異常機制主要依賴於 try、catch、finally、throw、throws 五個關鍵字。
Java異常分爲兩種: Checked異常 和 Runtime異常。
異常處理機制
如果執行try塊裏的業務邏輯代碼時出現異常,系統自動生成一個異常對象,該異常對象被提交給Java運行時環境。這個過程被稱爲 拋出(throw)異常
當Java運行時環境收到異常對象時,會尋找能處理該異常對象的catch塊,如果找到合適的catch塊,則把該異常對象交給該catch塊處理。這個過程被稱爲捕獲(catch)異常
注意:
不管程序代碼塊是否處於try塊中,甚至包括catch塊中的代碼,只要執行該代碼塊時出現異常,系統總會自動生成一個異常對象。
如果程序沒有爲這段代碼定義任何的catch塊,則Java運行時環境無法找到處理該異常的catch塊,程序就此退出。
異常類的繼承體系
-
當Java運行時環境接收到異常對象後,會依次判斷該異常對象是否是catch塊後異常類或其子類的實例。
如果是,Java運行時環境將調用該catch塊來處理異常;
否則再次拿該異常對象和下一個catch塊裏的異常類進行比較。 -
在通常情況下,如果try塊被執行一次,則try塊後只有一個catch塊會被執行,絕不可能有多個catch塊被執行。
除非在循環中使用了continue 開始下一次循環,下一次循環又重新運行try塊,這纔會導致多次catch塊被執行。 -
注意:
try 和 if 語句不一樣。
try後的花括號 ({…})不可省略,即使try塊中只有一行代碼。
與之類似的是,catch塊後的 {} 也不可以省略。
try 塊裏聲明的變量是代碼塊內局部變量,它只在try塊內有效,在catch塊中不能訪問該變量。 -
Java常見的異常類的繼承關係
異常(Exception)和 錯誤(Error),它們都繼承Throwable父類
Error錯誤,一般指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,動態鏈接失敗等,這種錯誤無法恢復或不可能捕獲,將導致應用程序中斷。 -
注意: 異常捕獲時,一定要記住,先捕獲小異常,再捕獲大異常。
Java 7 提供的多異常捕獲
- 在Java 7 之前,每個catch塊只能捕獲一種類型的異常;但從Java 7之後,一個catch塊可以捕獲多種類型的異常。
注意:
捕獲多種類型的異常時,多個異常類型之間用“|” 隔開。
捕獲多種類型的異常時,異常變量有隱式的final修飾,因此程序不能對異常變量賦值。
public static void main(String[] args) {
try {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
int c = a / b;
System.out.println("Result = " + c);
} catch (NumberFormatException | IndexOutOfBoundsException | ArithmeticException e) {
System.out.println("The program occur NumberFormatException, IndexOutOfBoundsException and ArithmeticException");
//捕獲多異常時,異常變量默認有final修飾。
//下面代碼報錯。
//e = new ArithmeticException("Test");
} catch (Exception e) {
System.out.println("The unknow exception");
//捕獲一種異常時,異常變量沒有final修飾。
//下面代碼正確。
e = new RuntimeException("Test");
}
}
訪問異常信息
所有的異常對象,都包含如下幾個常用方法:
getMessage(); 返回該異常的詳細描述字符串。
printStackTrace(); 將該異常的跟蹤棧信息輸出到標準錯誤輸出。
printStackTrace(PrintStream s); 將該異常的跟蹤棧信息輸出到指定輸出流。
getStackTrace(); 返回該異常的跟蹤棧信息
使用finally回收資源
注意:
除非在try塊, catch塊中調用了退出虛擬機的方法。否則不管在try塊, catch塊中執行怎樣的代碼,出現怎樣的情況,異常處理的finally塊總會被執行
Java7 的自動關閉資源的try語句
Java7增強了try語句的功能------它允許在try關鍵字後緊跟一對圓括號,圓括號可以聲明、初始化一個或多個資源。此處的資源,指的是那些必須在程序結束時顯示關閉的資源(比如數據庫連接,網絡連接等),try語句在該語句結束時自動關閉這些資源。
注意:
爲了保證try語句可以正常關閉資源,這些資源實現類必須實現 AutoCloseable或 Closeable接口,實現這兩個接口就必須實現close()方法。
Checked異常和Runtime異常
Java的異常分爲兩大類:Checked異常和Runtime異常。
所有的RuntimeException類及其子類的實例被稱爲 Runtime異常。
不是RuntimeException類及其子類的異常實例被稱爲 Checked異常。
類別 | 常用異常類 |
---|---|
Error | AssertionError、OutOfMemoryError、StackOverflowError |
RuntimeException | AlreadyBoundException、ClassCastException、ConcurrentModificationException、IllegalArgumentException、IllegalStateException、IndexOutOfBoundsException、JSONException、NullPointerException、SecurityException、UnsupportedOperationException |
CheckedException | ClassNotFoundException、CloneNotSupportedException、FileAlreadyExistsException、FileNotFoundException、InterruptedException、IOException、SQLException、TimeoutException、UnknownHostException |
使用throws聲明拋出異常
使用throws聲明拋出異常的思路是:
當前方法不知道如何處理這種類型的異常,該異常應該由上一級調用者處理; 如果mian方法也不知道如何處理這種類型的異常,也可以使用throws聲明拋出異常,該異常將交給JVM處理。
JVM對異常的處理方法是,打印異常的跟蹤棧信息,並終止程序運行。
注意:
-
throws聲明拋出只能在方法簽名中使用,throws可以聲明拋出多個異常類,多個異常類之間以逗號隔開。
-
限制: 方法重寫時,兩小中的一條。
子類方法聲明拋出的異常類型應該是父類方法聲明拋出的異常類型的子類或相同,子類方法聲明拋出的異常不允許比父類方法聲明拋出的異常多。
使用throw拋出異常
-
throw 語句可以單獨使用,throw語句拋出的不是異常類,而是一個異常實例,而且每次只能拋出一個異常實例。
-
注意下面例子中的註釋:
public class ThrowTest {
public static void main(String[] args) {
try {
// 調用聲明拋出 Checked異常的方法,要麼顯示捕獲該異常
// 要麼在main()方法中再次聲明拋出
throwChecked(3);
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 調用聲明拋出Runtime異常的方法,可以顯示捕獲異常,也可以不理會該異常
throwRuntime(3);
}
public static void throwChecked(int a) throws Exception {
if (a > 0) {
// 自行拋出Exception異常
// 該代碼必須處於 try塊中,或者處於帶有throws聲明的方法中
throw new Exception("a 的值大於零,不符合要求");
}
}
public static void throwRuntime(int a) {
if (a > 0) {
// 自行拋出RuntimeException異常
// 既可以顯示捕獲異常,也可以完全不理會該異常,把該異常交給調用者處理
throw new RuntimeException("a 的值大於零,不符合要求");
}
}
}