【軟件構造】第七章第二節 錯誤與異常處理

第七章第二節 錯誤與異常處理

本節關注:Java中錯誤和異常處理的典 型技術——把原理落實到代碼上!html

Outline:

  • Java中的錯誤和異常(java.lang.throwable)
  • 異常
    • Runtime異常與其餘異常(Exception)
    • Checked異常和unchecked異常
  • checked異常的處理機制
  • 自定義異常

 Notes:

## Java中的錯誤和異常

【Throwable】java

  • Java.lang.throwable 
    • Throwable 類是 Java 語言中全部錯誤或異常的超類。
    • 繼承的類:extends Object。
    • 實現的接口:implements Serializable。
    • 直接已知子類:Error, Exception(直接已知子類:IOException、RuntimeException)。

 

 【Error】程序員

  • Error類描述不多發生的Java運行時系統內部的系統錯誤和資源耗盡狀況(例如,VirtualMachineError,LinkageError)。
  • 對於內部錯誤:程序員一般無能爲力,一旦發生,想辦法讓程序優雅的結束
  • Error的類型:
    • 用戶輸入錯誤
      • 例如:用戶要求鏈接到語法錯誤的URL,網絡層會投訴。
    • 設備錯誤
      • 硬件並不老是作你想作的。
      • 輸出器被關閉
    • 物理限制
      • 磁盤能夠填滿
      • 可能耗盡了可用內存
  •  典型錯誤:

 

## 異常(Exception)

  • 異常:程序執行中的非正常事件,程序沒法再按預想的流程執行。
  • 異常處理:
    • 將錯誤信息傳遞給上層調用者,並報告「案發現場」的信息。
    • return以外的第二種退出途徑:若找不到異常處理程序,整個系統徹底退出

【異常按結構層次的分類】數據庫

  • 運行時異常:由程序員處理不當形成,如空指針、數組越界、類型轉換
  • 其餘異常:程序員沒法徹底控制的外在問題所致使的,一般爲IOE異常,即找不到文件路徑等

【異常按處理機制角度的分類】編程

  • 爲何區分checked 和 unchecked:緣由其實很簡單,編譯器將檢查你是否爲全部的已檢查異常提供了異常處理機制,好比說咱們使用Class.forName()來查找給定的字符串的class對象的時候,若是沒有爲這個方法提供異常處理,編譯是沒法經過的。 
  • Checked exception:
    • 編譯器可幫助檢查你的程序是否已拋出或處理了可能的異常
    • 異常的向上拋出機制進行處理,若是子類可能產生A異常,那麼在父類中也必須throws A異常。可能致使的問題:代碼效率低,耦合度太高。
    • checked exception是須要強制catch的異常,你在調用這個方法的時候,你若是不catch這個異常,那麼編譯器就會報錯,好比說咱們讀寫文件的時候會catch IOException,執行數據庫操做會有SQLException等。
    • 對checked Exception處理機制    
      • 拋出:聲明是throws,拋出時throw    
      • 捕獲(try/catch):try出現異常,忽略後面代碼直接進入catch;無異常不進入catch;若catch中沒有匹配的異常處理,程序退出;若子類重寫了父類方法,父類方法沒有拋出異常,子類應本身處理所有異常而再也不傳播;子類從父類繼承的方法不能增長或更改異常
      • 處理:不能代替簡單的測試,儘可能苛刻、不過度細化、將正常處理與異常處理分開、利用好層次結構、早拋出晚捕獲、避免沒必要要的檢查
      • 清理現場、釋放資源(finally):finally中語句不論有無異常都執行

import java.io.*;
public class className
{
  public void deposit(double amount) throws RemoteException
  {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}
  • unchecked exception:
    • 程序猿對此不作任何事情,不得不重寫你的代碼(不須要在編譯時使用try-catch等機制處理)
    • 這類異常都是RuntimeException的子類,它們不能經過client code來試圖解決
    • 這種異常不是必須須要catch的,你是沒法預料的,好比說你在調用一個 list.szie()的時候,若是這個list爲null,那麼就會報NUllPointerException,而這個異常就是 RuntimeException,也就是UnChecked Exception
    • 常見的unchecked exception:JVM拋出,如空指針、數組越界、數據格式、不合法的參數、不合法的狀態、找不到類等

 

public class NullPointerExceptionExample {
    public static void main(String args[]){
        String str=null;
        System.out.println(str.trim());
    }
}

Exception in thread "main"  java.lang.NullPointerException

 【checked和unchecked總結】api

  • 當要決定是採用checked exception仍是Unchecked exception的時候,問一個問題: 「若是這種異常一旦拋出,client會作 怎樣的補救?」
    • 若是客戶端能夠經過其餘的方法恢復異常,那麼採用checked exception;
    • 若是客戶端對出現的這種異常無能爲力,那麼採用unchecked exception;
    • 異常出現的時候,要作一些試圖恢復它的動做而不要僅僅的打印它的信息。
  • 儘可能使用unchecked exception來處理編程錯誤:由於uncheckedexception不用使客戶端代碼顯式的處理它們,它們本身會在出現的地方掛起程序並打印出異常信息。
  • 若是client端對某種異常無能爲力,能夠把它轉變爲一個unchecked exception,程序被掛起並返回客戶端異常信息

 – Checked exception應該讓客戶端從中獲得豐富的信息。 數組

– 要想讓代碼更加易讀,傾向於用unchecked exception來處理程序中的錯誤網絡

 

 

## checked異常的處理機制

 【異常中的LSP原則】oracle

  • 若是子類型中override了父類型中的函數,那麼子類型中方法拋出的異常不能比父類型拋出的異常類型更普遍
  • 子類型方法能夠拋出更具體的異常,也能夠不拋出任何異常
  • 若是父類型的方法未拋出異常,那麼子類型的方法也不能拋出異常。
  • 其餘的參考第五章第二節的LSP

【利用throws進行聲明】ide

  • 使用throws聲明異常:此時須要告知你的client須要處理這些異常,若是client沒有handler來處理被拋出的checked exception,程序就終止執行。
  • 程序員必須在方法的spec中明確寫清本方法會拋出的全部checked exception,以便於調用該方法的client加以處理
  • 在使用throws時,方法要在定義和spec中明確聲明所拋出的所有checked exception,沒有拋出checked異常,編譯出錯,Unchecked異常和Error能夠不用處理。

【利用throw拋出一個異常】

  • 步驟:
    • 找到一個能表達錯誤的Exception類/或者構造一個新的Exception類
    • 構造Exception類的實例,將錯誤信息寫入
    • 拋出它
  • 一旦拋出異常,方法不會再將控制權返回給調用它的client,所以也無需考慮返回錯誤代碼

 【try-catch語句】

  • 使用 try 和 catch 關鍵字能夠捕獲異常。try/catch 代碼塊放在異常可能發生的地方。
  • try/catch代碼塊中的代碼稱爲保護代碼,
  • Catch 語句包含要捕獲異常類型的聲明。當保護代碼塊中發生一個異常時,try 後面的 catch 塊就會被檢查。
  • 若是發生的異常包含在 catch 塊中,異常會被傳遞到該 catch 塊,這和傳遞一個參數到方法是同樣。

【finally語句】

  • 場景:當異常拋出時,方法中正常執行的代碼被終止;但若是異常發生前曾申請過某些資源,那麼異常發生後這些資源要被恰當的清理,因此須要用finally語句。
  • finally 關鍵字用來建立在 try 代碼塊後面執行的代碼塊。
  • 不管是否發生異常,finally 代碼塊中的代碼總會被執行。
  • 在 finally 代碼塊中,能夠運行清理類型等收尾善後性質的語句。
  • finally 代碼塊出如今 catch 代碼塊最後:
  • 注意下面事項:
    • catch 不能獨立於 try 存在。
    • 在 try/catch 後面添加 finally 塊並不是強制性要求的。
    • try 代碼後不能既沒 catch 塊也沒 finally 塊。
    • try, catch, finally 塊之間不能添加任何代碼。
 1 public class ExcepTest{
 2   public static void main(String args[]){
 3     int a[] = new int[2];
 4     try{
 5        System.out.println("Access element three :" + a[3]);
 6     }catch(ArrayIndexOutOfBoundsException e){
 7        System.out.println("Exception thrown  :" + e);
 8     }
 9     finally{
10        a[0] = 6;
11        System.out.println("First element value: " +a[0]);
12        System.out.println("The finally statement is executed");
13     }
14   }
15 }

 

## 自定義異常

  • 若是JDK提供的exception類沒法充分描述你的程序發生的錯誤,能夠建立本身的異常類。
    • 若是但願寫一個檢查性異常類,則須要繼承 Exception 類。
    • 若是你想寫一個運行時異常類,那麼須要繼承 RuntimeException 類。

拋出檢查型異常:

拋出unchecked exception:

相關文章
相關標籤/搜索