Effective Java 第三版——71. 避免沒必要要地使用檢查異常

Tips
書中的源代碼地址:https://github.com/jbloch/effective-java-3e-source-code
注意,書中的有些代碼裏方法是基於Java 9 API中的,因此JDK 最好下載 JDK 9以上的版本。java

Effective Java, Third Edition

71. 避免沒必要要地使用檢查異常

許多Java程序員不喜歡檢查異常,但若是使用得當,他們能夠改進API和程序。 與返回碼和未檢查異常不一樣,它們迫使程序員處理異常問題,加強可靠性。 也就是說,在API中過分使用檢查異常會使它們使用起來不那麼使人愉快。 若是方法拋出檢查異常,則調用它的代碼必須在一個或多個catch塊中處理它們,或者聲明拋出它們並向上傳播。 不管哪一種方式,它都會給API的使用者帶來負擔。這種負擔在Java 8中加劇了,由於拋出檢查異常的方法不能直接在Stream中使用(條目45——48)。git

若是不能經過正確使用API來防止異常狀況,而且使用API的程序員在遇到異常時能夠採起一些有用的操做,那麼這種負擔是合理的。除非知足這兩個條件,不然可使用未檢查異常。做爲最後的檢驗(litmus test),能夠問問本身:程序員將如何處理異常。這是最好的辦法嗎?程序員

} catch (TheCheckedException e) {
    throw new AssertionError(); // Can't happen!
}

或者這樣:github

} catch (TheCheckedException e) {
    e.printStackTrace();        // Oh well, we lose.
    System.exit(1);

}

若是程序員不能作得更好,則須要一個未檢查異常。app

若是方法拋出的檢查異常是唯一的,那麼檢查異常給程序員帶來的額外負擔就會大得多。若是還有其餘方法,則該方法必須已經出如今try塊中,而且最多須要另外一個catch塊。若是一個方法拋出單個檢查異常,那麼這個異常就是該方法必須出如今try塊中,而且不能直接在Stream中使用。在這種狀況下,有必要問問本身是否有辦法避免檢查異常。性能

消除檢查異的最簡單方法是返回所需結果類型的Optional(條目 55)。該方法只返回一個空的Optional,而不是拋出一個檢查的異常。這種方法的缺點是,該方法不能返回任何詳細說明其沒法執行所需計算的額外信息。相反,異常具備描述性類型,而且能夠導出方法來提供額外的信息(條目 70)。測試

還能夠經過將拋出異常的方法分解爲兩個方法,將檢查異常轉換爲未檢查異常,第一個方法返回一個boolean值,表示是否拋出異常。 這個API重構將調用序列:線程

// Invocation with checked exception
try {
    obj.action(args);
} catch (TheCheckedException e) {
    ... // Handle exceptional condition
}

轉換爲:code

// Invocation with state-testing method and unchecked exception
if (obj.actionPermitted(args)) {
    obj.action(args);
} else {
    ... // Handle exceptional condition
}

這種重構並不老是合適的,可是它可使API更加溫馨。 雖而後者調用序列並不比前者更漂亮,但重構的API更靈活。 若是程序員知道調用將成功,或者知足於讓線程在失敗時終止,那麼重構也容許這個簡單的調用序列:對象

obj.action(args);

若是懷疑普通的調用序列會成爲常態,那麼API重構多是合適的。生成的API本質上與條目 69中的狀態測試方法API,而且適用與相同的警告:若是要在沒有外部同步的狀況下同時訪問對象,或者被外部轉換狀態,則此重構是不合適的,由於對象的狀態多是在對actionPermittedaction的調用之間進行更改。若是單獨的actionPermitted方法會重複action方法的工做,則可能會因性能緣由而排除重構。

總之,若是謹慎使用,檢查異常能夠提升程序的可靠性;當過分使用,會使API難以使用。若是調用者沒法從失敗中恢復,則拋出未檢查異常。若是恢復是可能的,而且但願強制調用者處理異常條件,那麼首先考慮返回Optional的。只有當在失敗的狀況下,沒法提供充分的信息時,才應該拋出一個檢查的異常。

相關文章
相關標籤/搜索