Tips
書中的源代碼地址:https://github.com/jbloch/effective-java-3e-source-code
注意,書中的有些代碼裏方法是基於Java 9 API中的,因此JDK 最好下載 JDK 9以上的版本。java
Java提供了三種可拋出異常對象:已檢查異常( checked exceptions)、運行時異常(runtime exceptions)和虛擬機錯誤(errors)。程序員們對何時使用每種拋出的異常比較困惑。雖然決策並不老是明確的,可是有一些通用規則能夠提供有力的指導。git
決定是否使用已檢查異常或未檢查異常的基本規則是:對於能夠合理地預期調用者將從中恢復的條件,使用已檢查異常。經過拋出一個已檢查的異常,能夠強制調用者在catch子句中處理異常,或者將其傳播出去。所以,聲明要拋出方法的每一個已檢查異常都有力地向API用戶代表,關聯的條件是調用該方法的一個可能的結果。程序員
經過向用戶提供已檢查異常,API設計器提供了從異常條件中恢復的要求。用戶能夠經過捕獲異常並忽略異常來無視這個要求,但這一般不是一個好主意(條目 77)。github
有兩種未檢查的可拋出的異常:運行時異常和虛擬機錯誤。它們在行爲上是同樣的:都是可拋出的,一般不該該被捕獲。若是程序拋出未檢查的異常或錯誤,一般狀況下是沒法恢復的,繼續執行的話弊大於利。若是程序沒有捕捉到這樣的可拋出的異常,會致使當前線程掛起或中止,併發出適當的錯誤消息。編程
使用運行時異常來指出編程錯誤。 絕大多數運行時異常表示違反了先決條件(precondition violation)。 違反先決條件的緣由僅僅是客戶端API沒法遵照API規範創建的約定。 例如,數組訪問的約定指定數組索引必須介於0和數組長度減去1之間)。 ArrayIndexOutOfBoundsException異常指出違反了此先決條件。數組
這個建議的一個問題是,你並不老是清楚是在處理可恢復的異常仍是編程錯誤。例如,考慮資源耗盡的狀況,這多是由編程錯誤(如分配一個不合理的大數組)或真正的資源短缺形成的。若是資源枯竭是因爲臨時短缺或需求臨時增長形成的,這種狀況極可能是能夠恢復的。對於API設計人員來講,判斷給定的資源耗盡實例是否容許恢復是一個問題。若是你認爲某個條件可能容許恢復,請使用已檢查的異常;若是不能,則使用運行時異常。若是不清楚是否能夠恢復,最好使用未檢查的異常,緣由將在條目 71中討論。併發
雖然Java語言規範沒有要求,但有一個強烈的約定,即保留錯誤(errors)以供JVM使用,以指示資源缺陷,不變性失敗(invariant failures),以及其餘沒法繼續執行的條件。 鑑於幾乎廣泛接受這種約定,最好不要實現任何新的Error子類。 所以,實現全部未經檢查的可拋出異常應該是RuntimeException的子類(直接或間接子類)。 不只不該該定義Error子類,並且除了AssertionError以外,也不該該拋出它們。線程
能夠定義一個可拋出的異常,不是Exception、RuntimeException或Error的子類。JLS不直接處理這些可拋出類,而是隱式地指定它們做爲普通的檢查異常(它們是Exception的子類,但不是RuntimeException)。那麼,何時應該使用這樣的可拋出異常?總之,永遠不會。與普通的檢查異常相比,它們沒有任何好處,只會讓API的使用者感到困惑。設計
API設計者常常忘記異常是也是徹底成熟的對象,能夠在其上定義任意方法。此類方法的主要用途是提供捕獲異常的代碼,其中包含有關致使拋出異常的條件的其餘信息。 在沒有這樣的方法的狀況下,已知程序員解析異常的字符串表示以發現附加信息。 這是很是糟糕的作法(條目 12)。 可拋出的類不多指定其字符串表示的細節,所以字符串表示可能因實現而異,也可能因發佈而異。 所以,解析異常的字符串表示的代碼多是不可移植且脆弱的。code
由於檢查異常一般表示可恢復的異常條件,因此對它們來講,提供信息的方法來幫助調用者從異常條件中恢復尤其重要。例如,假設當使用禮品卡購物的嘗試因爲資金不足而失敗時,拋出一個已檢查的異常。異常應該提供一個訪問器方法來查詢差額的數量。這會使調用者可以將金額傳遞給購物者。有關此主題的更多信息,請參見條目 75。
總而言之,爲可恢復的異常條件拋出已檢查異常,爲編程錯誤拋出未檢查異常。當有疑慮不肯定時,拋出未檢查的異常。不要定義任何既不是已檢查異常也不是運行時異常的可拋出異常。提供已檢查異常的方法,用來幫助恢復。