《瘋狂Java講義(第4版)》-----第10章【異常處理】
異常處理可以提高程式的健壯性、呈現功能給使用者更加友好。Java異常機制主要關鍵字:try、catch、finally、throw、throws。throws關鍵字在宣告方法時候使用,用於宣告該方法可能丟擲的異常。而throw關鍵字用於丟擲一個實際的異常。Java把異常分為兩種,Checked異常(可以在編譯階段被處理的異常)和Runtime異常,強制程式處理所有的Checked異常。
異常處理機制
try…catch捕獲異常
下面程式碼中,try塊裡面如果有異常,系統就生成一個異常物件,交給Java執行時環境,這就時丟擲異常。Java執行時環境收到異常物件後,去找能處理該異常的catch塊,交給相應的catch塊處理異常,這就是捕獲異常。如果無法找到處理該異常的catch塊,執行時環境終止,Java程式退出。
try{
//業務程式碼
}catch(Exception e){
//處理異常
}
注意:try塊和catch塊僅有一句程式碼時花括號也不可以省略。try塊裡定義變數是try塊的區域性變數,其他部分的程式無法訪問。
Java異常類的繼承關係
Error錯誤一般是指與虛擬機器有關的問題,如系統崩潰、虛擬機器錯誤、動態連結失敗等,這種錯誤無法恢復或不可捕獲,將會導致程式中斷。try…catch捕獲的異常是Exception類的。
【捕獲處理異常示例程式碼】 注意捕獲異常的catch塊的順序,先捕獲小異常,再捕獲大異常,否則編譯報錯。
public class Hello{ 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("您輸入的兩整數相除的商是: "+c); }catch(IndexOutOfBoundsException ie){ System.out.println("輸入的引數個數小於2,陣列越界!"); }catch(NumberFormatException ne){ System.out.println("數字格式不正確,輸入的引數應該是整數"); }catch(ArithmeticException ae){ System.out.println("算術異常"); }catch(Exception e){ System.out.println("未知異常"); } } }
Java7新增的多異常捕獲
捕獲多種異常時,用 | 隔開,異常變數預設用了隱式的final修飾,不能對異常變數重新賦值。
public class Hello{ 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("您輸入的兩整數相除的商是: "+c); }catch(IndexOutOfBoundsException | NumberFormatException | ArithmeticException e){ System.out.println("陣列越界、數字格式不對或算術異常"); //編譯報錯,異常變數預設有final修飾,不可重新賦值 //e = new IndexOutOfBoundsException(); }catch(Exception e){ System.out.println("未知異常"); e = new Exception();//這是正確的,不是多異常捕獲,異常變數沒有final隱式修飾 } } }
訪問異常資訊
所有的異常都有獲取或列印異常資訊的方法,檢視他們繼承的父類Throwable就知道了,檢視官方文件如下:
public class Hello{
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("您輸入的兩整數相除的商是: "+c);
}catch(IndexOutOfBoundsException | NumberFormatException | ArithmeticException e){
System.out.println("陣列越界、數字格式不對或算術異常");
System.out.println(e.getMessage());
e.printStackTrace();
}catch(Exception e){
System.out.println("未知異常");
}
}
}
使用finally回收資源
- try塊裡如果打開了物理資源(比如資料庫連線、網路連線、磁碟檔案等),需要顯式回收,Java的垃圾回收機制不回收物理資源,只回收堆記憶體中的物件佔用的記憶體。
- 不管try塊的程式碼是否有異常,不管catch塊是否被執行,甚至try塊、catch塊中執行了return語句,finally塊總會被執行(有一種特例:在catch塊執行System.exit(1)退出虛擬機器,finally塊就不執行了)。有try塊的話,catch塊和finally塊必須至少有其一。示例程式碼見該書375頁。
- 一般不要在finally塊中使用return語句或throw語句,一旦finally塊中使用了return語句或throw語句,會導致try塊、catch塊的return、throw語句失效。因為,try塊、catch塊遇到return、throw語句的時候就會找finally塊,如果沒有finally塊,就執行return或throw語句結束方法,如果有finally塊,就先去執行finally塊,再跳回到執行try塊、catch塊程式碼,而如果finally塊裡有return語句或throw語句把方法結束掉了,那就跳不回去了!示例程式碼見該書376頁。
異常處理巢狀
try、catch、finally三個塊中都可以進行try…catch…finally巢狀,沒有特別限制。
Java7自動關閉資源的try語句
與375頁關閉資源語句對比,377頁Java7自動關閉資源的方法更加簡潔。具體看377頁講解部分及示例程式碼。
Checked異常與Runtime異常
- Runtime異常:所有Runtime類及其子類的例項
- Checked異常:非Runtime異常 對於程式中的Checked異常,Java要求必須顯式捕獲或者顯式宣告丟擲該異常。
使用throws宣告丟擲異常
使用throws宣告丟擲異常的思路是:當前方法不處理異常,交給上一級呼叫者處理;如果main方法也不知道怎麼處理異常,交給JVM處理。JVM處理異常的方式是:列印異常的跟蹤棧資訊,終止程式執行。
程式中使用了throws宣告丟擲異常,就表明本級方法不處理該異常,讓上一級呼叫者處理,就不需要再用顯示的try…catch捕獲異常了(筆者試了一下,同時用也行!!)。
方法重寫時,子類方法宣告丟擲的異常應該比父類宣告丟擲的異常型別小或相同。
使用throw丟擲異常
程式出錯的時候,系統會自動丟擲異常;除此之外,系統也允許程式用throw語句自行丟擲異常。注意throw丟擲的異常類例項,與throws宣告丟擲異常類不同。
如果throw語句丟擲的時Checked異常,該throw語句要麼用try塊顯式處理,要麼放在一個帶throws宣告丟擲的方法中。如果throws語句丟擲的是Runtime異常,該throw語句可以放在try塊或宣告丟擲的方法中,也可以完全不理會該異常。示例程式碼見381頁。