在整個異常處理機制中,異常在系統中進行傳遞,傳遞到程序員認為合適的
位置,就捕獲到該異常,然后進行邏輯處理,使得項目不會因為出現異常而崩潰。
為了捕獲異常並對異常進行處理,使用的捕獲異常以及處理的語法格式為:
try{
//邏輯代碼
}catch(異常類名 參數名){
//處理代碼
}
在該語法中,將正常的程序邏輯代碼書寫在 try 語句塊內部進行執行,這些
代碼為可能拋出異常的代碼,而 catch語句中書寫對應的異常類的類名,在 catch
語句塊內部書寫出現該類型的異常時的處理代碼。
程序執行到 try-catch 語句時,如果沒有發生異常,則完整執行 try 語句塊內
部的所有代碼,而 catch 語句塊內部的代碼不會執行,如果在執行時發生異常,
則從發生異常的代碼開始,后續的 try 語句塊代碼不會執行,而跳轉到該類型的
異常對應的 catch 語句塊中。
示例代碼如下:
String s = "123";
try{
int n = Integer.parseInt(s);
System.out.println(n);
}catch(NumberFormatException e){
System.out.println("該字符串無法轉換! ");
}
在 該 示 例 代 碼 中 , Integer類 的 parseInt 方 法 可 能 會 拋 出
NumberFormatException,因為 parseInt 方法的聲明如下:
public static int parseInt(String s) throws NumberFormatException
這里字符串 s轉換為 int沒有發生異常,則程序執行完 try語句塊內部的代碼,
程序的運行結果為: 123
如果將字符串對象 s 的值修改為”abc”,則運行上面的代碼,則 parseInt 方法
執行時將拋出 NumberFormatException,則調用 parseInt 方法語句后續的 try 語句
塊中的代碼不會執行,程序的執行流程跳轉到捕獲 NumberFormatException異常
的 catch 語句塊內部,然后執行該 catch 語句塊內部的代碼,則程序的執行結果
是:
該字符串無法轉換!
這就是最基本的捕獲異常和異常處理的代碼結構。使用 try 語句捕獲程序執
行時拋出的異常,使用 catch 語句塊匹配拋出的異常類型,在 catch 語句塊內部
書寫異常處理的代碼。
在實際程序中,也可以根據異常類型的不同進行不同的處理,這樣就需要多
個 catch 語句塊,其結構如下:
try{
//邏輯代碼
} catch(異常類名 1 參數名 1){
//處理代碼 1
} catch(異常類名 2 參數名 2){
//處理代碼 2
}
……
}catch(異常類名 n 參數名 n){
//處理代碼 n
}
例如:
String s = "123";
try{
int n = Integer.parseInt(s);
System.out.println(n);
char c = s.charAt(4);
System.out.println(c);
}catch(NumberFormatException e){
System.out.println("該字符串無法轉換! ");
}catch(StringIndexOutOfBoundsException e){
System.out.println("字符串索引值越界");
}
在執行時,按照 catch 語句塊書寫的順序從上向下進行匹配,直到匹配到合
適的異常就結束 try-catch 語句塊的執行。
在實際執行時,就可以根據捕獲的異常類型不同,書寫不同的異常處理的代
碼了。使用該語法時需要注意,如果這些異常類直接存在繼承關系,則子類應該
書寫在上面,父類應該書寫在下面,否則將出現語法錯誤。例如:
String s = "123";
try{
int n = Integer.parseInt(s);
System.out.println(n);
char c = s.charAt(4);
System.out.println(c);
}catch(Exception e){
}catch(NumberFormatException e){ //語法錯誤,異常已經被處理
System.out.println("該字符串無法轉換! ");
}catch(StringIndexOutOfBoundsException e){ //語法錯誤,異常已經被處
理
System.out.println("字符串索引值越界");
}
這里 Exception 類是所有異常類的父類,在匹配時可以匹配到所有的異常,
所有后續的兩個異常處理的代碼根本不會得到執行,所以將出現語法錯誤。正確
的代碼應該為:
String s = "123";
try{
int n = Integer.parseInt(s);
System.out.println(n);
char c = s.charAt(4);
System.out.println(c);
}catch(NumberFormatException e){
System.out.println("該字符串無法轉換! ");
}catch(StringIndexOutOfBoundsException e){
System.out.println("字符串索引值越界");
}catch(Exception e){
}
如果在程序執行時,所有的異常處理的代碼都是一樣的,則可以使用
Exception 代表所有的異常,而不需要一一進行區分,示例代碼如下:
String s = "123";
try{
int n = Integer.parseInt(s);
System.out.println(n);
char c = s.charAt(4);
System.out.println(c);
}catch(Exception e){
//統一的處理代碼
}
在實際使用時,由於 try-catch的執行流程,使得無論是 try 語句塊還是 catch
語句塊都不一定會被完全執行,而有些處理代碼則必須得到執行,例如文件的關
閉和網絡連接的關閉等,這樣如何在 try 語句塊和 catch 語句塊中都書寫則顯得
重復,而且容易出現問題,這樣在異常處理的語法中專門設計了 finally 語句塊來
進行代碼的書寫。語法保證 finally 語句塊內部的代碼肯定獲得執行,即使在 try
或 catch 語句塊中包含 return 語句也會獲得執行,語法格式如下:
finally{
//清理代碼
}
該語法可以和上面的兩種 try-catch語句塊匹配,也可以和 try 語句匹配使用,
和 try 語句塊匹配的語法格式如下:
try{
//邏輯代碼
}finally{
//清理代碼
}
這樣在執行時,無論 try 語句塊中的語句是否發生異常, finally 語句塊內部
的代碼都會獲得執行。
而只書寫 finally 而不書寫 catch 則會導致異常的丟失,所以最常用的異常處
理的語法格式還是如下語法:
try{
//邏輯代碼
}catch(異常類名 參數){
//異常處理代碼
}finally{
//清理代碼
}
這樣就是整個異常處理部分的邏輯代碼、異常處理代碼和清理的代碼成為一
個整體,使得程序代碼更加顯得緊湊,便於代碼的閱讀和使用。
最后,介紹一下使用異常處理語法時需要注意的問題:
1、書寫在 try 語句塊內部的代碼執行效率比較低。所以在書寫代碼時,只把可能
出現異常的代碼書寫在 try 語句塊內部。
2、如果邏輯代碼中拋出的異常屬於 RuntimeException 的子類,則不強制書寫在
try 語句塊的內部,如果拋出的異常屬於非 RuntimeException 的子類,則必須進
行處理,其中書寫在 try 語句塊是一種常見的處理方式。
3、 catch語句塊中只能捕獲 try 語句塊中可能拋出的異常,否則將出現語法錯誤。
聲明自定義異常類
如果 JDK API中提供的已有的異常類無法滿足實際的使用需要,則可以根據
需要聲明自定義的異常類來代表項目中指定類型的異常。
異常類在語法上要求必須直接或間接繼承 Exception,可以根據需要選擇繼承
Exception 或 RuntimeException 類,這樣也設定了自定義異常類的類型。如果直
接繼承 Exception,則屬於必須被處理的異常,如果繼承 RuntimeException,則不
強制必須被處理。當然,可以根據需要繼承其它 Exception 的子類。
在編碼規范上,一般將異常類的類名命名為 XXXException,其中 XXX 用來
代表該異常的作用。
示例代碼如下:
/**
* 自定義異常類
*/
public class MyException extends RuntimeException {}
自定義異常類的用途,則完全由程序員進行規定,可以在出現該異常類型的條件
時拋出該異常,則就可以代表該類型的異常了。
在實際的項目中,有些時候還需要設計專門的異常類體系,來代表各種項目中需
要代表的異常情況。
異常處理方式
前面介紹了異常處理機制的相關語法,但是當出現異常時,如何進行處理是
語法無法解決的問題,下面就介紹一下異常處理的方式。
異常處理,顧名思義就是將出現的異常處理掉,但是根據異常出現的位置以
及異常的類型不同,會出現很多的方式,依次介紹如下:
1、不處理
該處理方式就是只捕獲異常不進行處理。不推薦使用該方式。
例如:
String s = “abc”;
try{
int n = Integer.parseInt(s);
}catch(Exception e){
}
對於這樣的處理,該異常被忽略掉了,有可能會影響后續邏輯的執行執行。該種
處理方式一般被初學者使用的比較多。
2、直接處理掉
如果具備處理異常的條件,則可以根據不同的異常情況將該異常處理掉,例如給
出用戶錯誤原因的提示等或根據邏輯上的需要修正對應的數值。
例如:
/**