Java :異常處理
異常的分類
非檢查異常(unckecked exception):Error 和 RuntimeException 以及他們的子類。javac在編譯時,不會提示和發現這樣的異常,不要求在程式處理這些異常。所以如果願意,我們可以編寫程式碼處理(使用try…catch…finally)這樣的異常,也可以不處理。對於這些異常,我們應該修正程式碼,而不是去通過異常處理器處理 。這樣的異常發生的原因多半是程式碼寫的有問題。如除0錯誤ArithmeticException,錯誤的強制型別轉換錯誤ClassCastException,陣列索引越界ArrayIndexOutOfBoundsException,使用了空物件NullPointerException等等。
檢查異常(checked exception):除了Error 和 RuntimeException的其它異常。javac強制要求程式設計師為這樣的異常做預備處理工作(使用try…catch…finally或者throws)。在方法中要麼用try-catch語句捕獲它並處理,要麼用throws子句宣告丟擲它,否則編譯不會通過。如SQLException , IOException,ClassNotFoundException 等。
簡言之,RuntimeException的子類異常是程式碼本身的問題導致的,不期望使用異常處理。而Exception的直接子類應使用異常處理
異常處理
try{
業務邏輯;
業務邏輯;
業務邏輯;//哪裡發生異常就在哪裡終止
......
}catch(異常型別1 e){//依次匹配,匹配時支援父類匹配
處理1;//也可再次丟擲throw e;
}catch(異常型別2 e){//丟擲的異常被catch到,就不再往下匹配
處理2;
}catch(異常型別3 e){
處理3;
}finally{
執行;
}
finally塊不管異常是否發生,只要對應的try執行了,則它一定也執行。只有一種方法讓finally塊不執行:System.exit()。因此finally塊通常用來做資源釋放操作:關閉檔案,關閉資料庫連線等等
良好的程式設計習慣是:在try塊中開啟資源,在finally塊中清理釋放這些資源
在catch中return
使用try……catch……finally進行異常處理時,如果在某個catch中return,finally中的內容仍然會得到執行,在除錯中可以看到,程式執行至return語句時,跳轉至finally中,執行完後在迴歸至return執行,finally中的程式碼可以修改資料。然而return在先前已經產生,所以return的結果是finally未執行時的狀態(finally中沒有return)
示例
public class Main {
private static String s = "";
public static void main(String[] args) {
System.out.println(test());
System.out.println("s ;"+s);
}
private static String test(){
int [] error = new int[5];
try {
System.out.println(error[5]);
}catch (Exception e){
System.out.println("捕捉到一隻異常");
s = "catch";
return s;
}finally {
s = "finally";
}
return s;
}
}
//輸出為
捕捉到一隻異常
catch
s :finally
- catch、finally中均有return
private static String test(){
int [] error = new int[5];
try {
System.out.println(error[5]);
}catch (Exception e){
System.out.println("捕捉到一隻異常");
s = "catch";
return s;
}finally {
s = "finally";
return s;
}
}
//輸出為
捕捉到一隻異常
finally
s :finally
try、catch、finally中出現流程控制語句return、break、continue等會使程式流程十分詭異 參考Java 中的異常和處理詳解
總之
- 不要在fianlly中使用return
- 不要在finally中丟擲異常
- 減輕finally的任務,不要在finally中做一些其它的事情,finally塊僅僅用來釋放資源是最合適的
- 將盡量將所有的return寫在函式的最後面,而不是try … catch … finally中
異常捕捉機制
異常的丟擲
- 在方法首部宣告可能丟擲的異常
- 由於Java的多型性,當子類重寫父類的帶有 throws宣告的函式時,其throws宣告的異常必須在父類異常的可控範圍內,即用於處理父類的throws方法的異常處理,必須也適用於子類的這個帶throws方法
- 用try與catch包裹可能丟擲異常的程式碼塊
- 手動丟擲異常
- throw new 異常型別();
異常與繼承
- 為了保證多型性下的父類變數不會遺漏處理某個子類方法特有的異常,子類重寫父類的方法時,不能丟擲比父類方法更多的異常
- 子類的構造方法必須宣告父類構造方法丟擲的所有異常,因為子類構造方法會呼叫父類構造方法。
- 子類構造方法可以丟擲更多異常,因為構造方法的呼叫一般是直接的,至於子類的構造方法間接呼叫,已經由第二條保證
自定義異常
如果要自定義異常類,則擴充套件Exception類即可,因此這樣的自定義異常都屬於檢查異常(checked exception)。如果要自定義非檢查異常,則擴充套件自RuntimeException。
按照國際慣例,自定義的異常應該總是包含如下的建構函式:
- 一個無參建構函式
- 一個帶有String引數的建構函式,並傳遞給父類的建構函式
- 一個帶有String引數和Throwable引數,並都傳遞給父類建構函式
- 一個帶有Throwable 引數的建構函式,並傳遞給父類的建構函式。
2018/7/28
2018/8/2更新