充分發揮異常的優點,可以提高程式的可讀性、可靠性和可維護性。如果使用不當,它們也會帶來負面影響。
異常應該只用於異常的情況下,它們不應該用於正常的控制流。同理,設計良好的 api 不應該強迫客戶端為了正常的控制流而使用異常。如果乙個類有狀態相關的方法,即只有在特定的不可預知的情況下才能呼叫的方法,這個類也應該有個狀態測試的方法,用於指示是否可以呼叫那個狀態相關的方法。比如 iterator 介面中狀態相關的 next 方法和狀態測試的 hasnext 方法。
如果期望呼叫者能夠適當地恢復,就應該使用受檢異常。通過丟擲受檢異常,強迫呼叫者在乙個 catch 子句中處理該異常,或者將它傳播出去。
通常用執行時異常來表示程式設計錯誤,多數執行時異常表示前提違例 precondition violation。
error 通常用於表示資源不足、約束失敗,或其他表示程式無法繼續執行的情況。
過分地使用受檢異常,會使 api 用起來非常不方便。
好處是:
1. 使得 api 更加易於學習和使用,因為與程式設計師已經熟悉的習慣用法一致。
2. 少乙個類,省記憶體。
經常被重用的異常有:
異常含義
illegalargumentexception
引數非法
illegalstateexception
狀態錯誤
nullpointerexception
禁止 null 的時候引數為 null
indexoutofbound***ception
下標引數越界
concurrentmodificationexception
禁止併發修改時,檢測到物件的併發修改
unsupportedoperationexception
物件不支援使用者請求的方法
注意:一定要確保丟擲異常的條件,和這些異常的文件描述一致。
如果方法丟擲的異常與它所執行的任務沒有明顯的聯絡,這種情形會讓人不知所措。當方法傳遞由底層抽象丟擲的異常時,往往會發生這種情況。除了讓人困惑之外,也讓實現細節汙染了更高層的 api。如果高層實現後續發生了變化,它所丟擲的異常也會變化,從而潛在地破壞現有的客戶端程式。
為了避免這個問題,更高層的實現應該捕獲低層的異常,同時丟擲按照高層抽象解釋的異常。這種做法稱為「異常轉譯」。
一種特殊的異常轉譯就是常見的「異常鏈」,高層異常提供訪問方法(throwable.getcause)來獲得低層的異常。
異常不能被濫用,能避免最好,比如呼叫低層方法之前先做引數檢查。
沒有文件,其他人就很難有效地使用你的類和介面。
throws 子句中應該只有受檢異常,不能包含非受檢異常。但是,文件裡應該既有受檢異常描述,也有常見的非受檢異常描述。
異常的細節資訊應該包含所有「對該異常有貢獻」的引數和域的值。
定製異常的時候,可以直接在構造器中輸入關鍵引數資訊,並提供訪問這些資訊的方法。
一般而言,失敗的方法呼叫應該使物件保持在被呼叫之前的狀態。具有這種屬性的方法被稱之為具有「失敗原子性」。如何做到失敗原子性呢?
1. 使用不可變的物件。
2. 調整計算處理的順序,讓可能失敗的部分發生在狀態修改之前。
3. 修改狀態之前檢查引數有效性,比如 stack 的 pop 方法會在方法開頭檢查棧大小。
4. 編寫異常恢復**。
如果 api 的方法不具有失敗原子性,就應該在 api 文件中指明失敗後物件會處於什麼樣的狀態。
空的 catch 塊會使異常達不到應有的目的。通常會在 catch 塊中記錄日誌和監控,如果真要忽略,也有寫乙個注釋說明為何忽略。
Effective Java 讀書筆記
第二章 建立與銷毀物件 1 考慮用靜態工廠方法代替構造器 優點 1 有名稱 2 不必在每次呼叫他們的時候都建立乙個新的物件 3 他們可以返回原返回型別的任何子型別物件 4 使 更簡潔 缺點 1 類如果不含公有的或者受保護的構造器,就不能被子類化 2 與其他的靜態方法實際上沒有任何區別,不能一眼就看出...
Effective java 讀書筆記
一本書看了不少時間,終於這兩天看完了,看的眼睛生疼,估計也就領略了全書1 5的精華。這本書確確實實是本好書,就像剛剛牙牙學語的孩子必須接受父母的教導,電源插頭不可以摸,熱水不可以直接喝等等,很多經驗之談,給人確確實實的思考和應用。盡量多的編碼。如同讀書一樣,沒有一定的 量的積累,很難成為乙個好的程式...
Effective Java讀書筆記二
我們在設計類的時候,有些類難免會有許多的字段 fields 而這些字段可能需要在建立物件的時候對它們進行賦值。一般我們會考慮兩種方式 使用建構函式或者使用setter方法。使用建構函式的缺點很明顯,如果我們的字段過多,那麼就會讓建構函式的引數過多,在這種情況下,不但不容易理解和閱讀,而且非常容易出錯...