處理錯誤
Java中,如果某個方法不能採用完整的途徑完成它的任務,就可以通過另外一個路徑退出方法。在這種情況下,方法並不返回任何值,而是丟擲(throw)一個封裝了錯誤資訊的物件。需要注意的是,這個方法將會立刻退出,並不返回任何值。此外,呼叫這個方法的程式碼也將無法繼續執行,取而代之的是,異常處理機制開始搜尋能夠處理這種異常狀況的異常處理器(exception handler)。
異常分類
Java中,異常物件都是派生於Throwable類的一個例項。異常的層次結構如下所示
所有的異常都是由Throwable繼承而來,但在下一層立即分解為兩個分支:Error和Exception。- Error類層次結構描述了Java執行時系統的內部錯誤和資源耗盡錯誤。應用程式不應該丟擲這種型別的物件。如果出現了這樣的內部錯誤,除了通告給使用者,並盡力使程式安全地終止之外,再也無能為力了。這種情況很少出現。
- 在設計Java程式時,需要關注Exception層次結構。這個層次結構又分為兩個分支:一個分支派生於RuntimeException;另一個分支包含其他異常。劃分兩個分支的規則是:由程式錯誤導致的異常屬於RuntimeException;而程式本身沒有問題,但由於像I/O錯誤這類問題導致的異常屬於其他異常。
- 派生於RuntimeException的異常包括:
- 錯誤的型別轉換
- 陣列訪問越界
- 訪問null指標
- 不是派生於RuntimeExcepiton的異常包括:
- 試圖在檔案尾部後面讀取資料
- 試圖開啟一個不存在的檔案
- 試圖根據給定的字串查詢Class物件,而這個字串表示的類並不存在
Java語言規範將派生於Error類或RuntimeException類的所有異常稱為非受查(unchecked)異常,所有其他的異常稱為受查(checked)異常。編譯器將核查是否為所有的受查異常提供了異常處理器。
注: RuntimeException這個名字很容易讓人混淆。實際上,現在討論的所有錯誤都發生在執行時。
注: 如果在子類中覆蓋了超類的一個方法,子類方法中宣告的受查異常不能比超類方法中宣告的異常更通用(也就是說,子類方法中可丟擲更特定的異常,或者根本不丟擲任何異常)。特別需要說明的是,如果超類方法沒有丟擲任何受查異常,子類也不能丟擲任何受查異常。
捕獲異常
編譯器嚴格執行throws說明符。如果呼叫了一個丟擲受查異常的方法,就必須對它進行處理,或者繼續傳遞。通常,應該捕獲那些知道如何處理的異常,而將那些不知道怎樣處理的異常繼續進行傳遞。
如果想傳遞一個異常,就必須在方法的首部新增一個throws說明符,以便告知呼叫者這個方法可能會丟擲異常。
finally子句
當程式碼丟擲一個異常時,就會終止方法中剩餘程式碼的處理,並退出這個方法的執行。如果方法獲得了一些本地資源,並且只有方法自己知道,又如果這些資源在退出方法之前必須被回收,那麼就會產生資源回收問題。這時一般使用finally子句。不管是否有異常被捕獲,finally子句中的程式碼都被執行。
使用斷言
在一個具有自我保護能力的程式中,斷言很常用。
斷言機制允許在測試期間向程式碼中插入一些檢查語句。當程式碼釋出時,這些插入的檢測語句將會被自動地移走。
Java語句引入了關鍵字assert。這個關鍵字有兩種形式:
assert 條件;
以及 assert 條件:表示式;
複製程式碼
這兩種形式都會對條件進行檢測,如果結果為false,則丟擲一個AssertionError異常。在第二種形式中,表示式將被傳入AssertionError的構造器,並轉換成一個訊息字串。
在Java語言中,給出了3種處理系統錯誤的機制:
- 丟擲一個異常
- 日誌
- 使用斷言
什麼時候應該選擇使用斷言呢?
- 斷言失敗是致命的、不可恢復的錯誤
- 斷言檢查只用於開發和測試階段
斷言是一種測試和除錯階段所使用的戰術性工具;而日誌記錄是一種在程式的整個宣告週期都可以使用的策略性工具。
### 記錄日誌
用來替代System.out.println方法,解決頻繁插入刪除System.out.println方法的問題。
log4j?