1. 程式人生 > >《瘋狂Java講義》學習筆記(九)異常處理

《瘋狂Java講義》學習筆記(九)異常處理

1、異常概述

  • 異常機制已經成為判斷一門程式語言是否成熟的標準,目前主流的程式語言都提供了成熟的異常機制,增加了異常處理機制後的程式有更好的容錯性,更加健壯
  • Java的異常機制主要依賴於:try、catch、finally、throws和throw
  • Java7進一步增強了異常處理機制的功能,包括帶資源的try語句、捕獲更多異常的catch
  • Java將異常分為兩種,Checked異常和Runtime異常,Checked異常都是可以在編譯階段被處理的異常,程式強制要求處理;而Runtime異常是執行時產生的異常

2、異常處理機制

  • 使用try…catch捕獲異常
    try{…}catch(Exception e){…}
    如果執行try塊裡的業務邏輯程式碼時出現異常,系統自動生成一個異常物件,該異常物件被提交給Java執行時環境,這個過程被稱為丟擲(throw)異常
    當Java執行時環境收到異常物件時,會尋找能處理該異常物件的catch塊,如果找到合適的則把該異常物件交給該catch塊處理,這個過程被稱為捕獲異常,否則執行時環境終止,Java程式也將退出

3、異常的繼承關係

  • Java把所有非正常情況分成兩種:異常(Exception)和錯誤(Error),它們都是繼承Throwable父類
  • Error錯誤,一般是指與虛擬機器相關的問題,如系統崩潰、虛擬機器錯誤、動態連結失敗等,這種錯誤無法恢復或不可能捕獲,將導致應用程式中斷;通常應用程式無法處理這些錯誤,因此也無法捕獲
  • 開發中常遇到的記憶體溢位是屬於錯誤(Error)
    第一種:OutOfMemoryError: PermGen space記憶體空間不足,如一次性載入太多資訊,或載入專案太多
    第二種:OutOfMemoryError: Java heap spacejava虛擬機器建立的物件太多,在進行垃圾回收之間,虛擬機器分配的到堆記憶體空間已經用滿了
    第三種:OutOfMemoryError:unable to create new native thread一般很少出現,可能由於分配給JVM記憶體與系統本身比例問題引起
  • Java7可以提供更多異常捕獲
    try{…}catch(IndexOutOfBoundsException|NumberFormatException|ArithmeticException ie){…}
  • 訪問異常資訊
    getMessage():返回該異常的詳細描述字串
    printStackTrace():將該異常的跟蹤棧資訊輸出到標準錯誤輸出
    printStackTrace(PrintStream s):將該異常的跟蹤資訊輸出到指定輸出流
    getStackTrace():返回該異常的跟蹤棧資訊

4、finally塊

try{
    ...
}catch(Exception e){
    ...
}finally{ ... }
  • 不管try塊中的程式碼是否出現異常,也不管哪一個catch塊被執行,甚至在try塊或catch塊中執行了return、throw語句,finally塊總是被執行
  • 異常處理語法結構中只有try塊是必須的,catch塊和finally塊都是可選的,但兩者至少出現其中之一;可以有多個catch塊,catch塊必須位於try之後,finally必須位於所有catch塊之後;
  • 如果在異常處理程式碼中使用System.exit(1)語句來退出虛擬機器,則finally塊將失去執行的機會
  • 在通常情況下,不要在finally塊中使用如return或throw等導致方法終止的語句,否則會導致try塊、catch塊中的return、throw語句失效

5、Java7自動關閉資源的try語句

try(BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));){
    System.out.println(br);
} catch (Exception e) {
    e.printStackTrace();
}
  • Java7增強了try語句的功能,允許在try關鍵字後緊跟一對圓括號宣告、初始化一個或多個資源,try語句在該語句結束時自動關閉這些資源;而且這些資源實現類必須實現AutoCloseable或Closeable介面,實現這兩個介面就必須實現close()方法
  • 以上的BufferedReader都是實現了Closeable介面的,即使沒有finally塊也會自動關閉資源

6、Checked異常和Runtime異常體系

  • 所有的RuntimeException類及其子類的例項被稱為Runtime異常;非RuntimeException類及其子類的異常例項則被稱為Checked異常
  • Checked異常處理方式:
    當前方法明確知道如何處理該異常,程式應該使用try…catch塊來捕獲該異常,然後再對應的catch塊中修復該異常
    當方法不知道如何處理這種異常,應該在定義該方法時丟擲該異常
  • Runtime異常則無須顯示宣告丟擲,程式也可以通過try…catch塊來捕獲

7、使用throws宣告丟擲異常

public class ThrowsTest{
    public static main(String[] args)throws IOException{
        FileInputStream fis = new FileInputStream("a.txt");
    }
}
  • 當前方法不知道如何處理這種型別異常時可以使用throws宣告丟擲異常
  • 使用throws宣告丟擲異常時有一個限制:子類方法宣告丟擲的異常型別應該是父類方法宣告丟擲的異常型別的子類或相同,子類方法宣告丟擲異常不允許比父類方法宣告丟擲的異常多

8、使用throw丟擲異常

  • 當程式出現錯誤時,系統會自動丟擲異常,除此之外,Java也允許程式自行丟擲異常,使用throw語句來完成

9、自定義異常類

使用者自定義異常都應該繼承Exception基類,如果系統自定義Runtime異常,則應該繼承RuntimeException基類

public class MyException extends Exception{
    public MyException(){}
        public MyException(String msg){
        super(msg);
    }
    publc MyException(Throwable t){
        super(t);
    }
}

10、catch和throw同時使用

為了實現通過多方協作處理同一個異常的情形,可以在catch塊中結合throw語句來完成,將異常傳遞給下一個程式
Java7可以直接將捕獲的異常直接傳遞:

try{
    new FileOutputStream("a.txt");
}catch(Exception ex){
    ex.printStackTrack();
    throw ex;
}

11、異常鏈

public calSal() throws MyException{
    try{
        ...
    }catch(Exception e){
        throw new MyException(e);
    }
}

12、異常處理規則

  • 成功的異常處理應該實現4個目標:
    使程式程式碼混亂最小化
    捕獲並保留診斷資訊
    通知合適的人員
    採用合適的方式結束異常活動
  • 避免過度依賴異常:
    把異常和普通錯誤混淆在一起,不再編寫任何錯誤處理程式碼
    使用異常處理來替代流程控制
  • 不要使用過於龐大的try塊
    應該把大塊的try塊分割成多個可能出現異常的程式段落,並把它們放在單獨的try塊中