【軟件構造】第七章第二節 錯誤與異常處理
阿新 • • 發佈:2018-06-18
throw 之間 IE 程序猿 數組越界 它的 extends 希望 nds
第七章第二節 錯誤與異常處理
本節關註:Java中錯誤和異常處理的典 型技術——把原理落實到代碼上!
Outline:
- Java中的錯誤和異常(java.lang.throwable)
- 異常
- Runtime異常與其他異常(Exception)
- Checked異常和unchecked異常
- checked異常的處理機制
- 自定義異常
Notes:
## Java中的錯誤和異常
【Throwable】
- 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中語句不論有無異常都執行
- 對checked Exception處理機制
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總結】
- 當要決定是采用checked exception還是Unchecked exception的時候,問一個問題: “如果這種異常一旦拋出,client會做 怎樣的補救?”
- 如果客戶端可以通過其他的方法恢復異常,那麽采用checked exception;
- 如果客戶端對出現的這種異常無能為力,那麽采用unchecked exception;
- 異常出現的時候,要做一些試圖恢復它的動作而不要僅僅的打印它的信息。
- 盡量使用unchecked exception來處理編程錯誤:因為uncheckedexception不用使客戶端代碼顯式的處理它們,它們自己會在出現的地方掛起程序並打印出異常信息。
- 如果client端對某種異常無能為力,可以把它轉變為一個unchecked exception,程序被掛起並返回客戶端異常信息
– Checked exception應該讓客戶端從中得到豐富的信息。
– 要想讓代碼更加易讀,傾向於用unchecked exception來處理程序中的錯誤
## checked異常的處理機制
【異常中的LSP原則】
- 如果子類型中override了父類型中的函數,那麽子類型中方法拋出的異常不能比父類型拋出的異常類型更廣泛
- 子類型方法可以拋出更具體的異常,也可以不拋出任何異常
- 如果父類型的方法未拋出異常,那麽子類型的方法也不能拋出異常。
- 其他的參考第五章第二節的LSP
【利用throws進行聲明】
- 使用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:
【軟件構造】第七章第二節 錯誤與異常處理