天天看點

EffectiveJava(筆記八) 異常57. 隻針對異常的情況才使用異常58. 對可恢複的情況使用受檢異常, 對程式設計錯誤使用運作時異常59. 避免不必要地使用受檢的異常60. 優先使用标準的異常61. 抛出與抽象相對應的異常62. 每個方法抛出的異常都要有文檔63. 在細節消息中包含能捕獲失敗的資訊64. 努力使失敗保持原子性65. 不要忽略異常

57. 隻針對異常的情況才使用異常

try{
    int i = 0;
    while(true) range[i++].climb();
} catch(ArrayIndexOutOfBoundsException e) {
}
           

這段代碼有什麼作用? 看起來根本不明顯, 這正是它沒有真實被使用的原因, 這個循環企圖通路數組邊界之外的第一個數組元素時, 用抛出、 捕獲、 忽略ArrayIndexOutOfBoundsException的手段來達到終止無限循環的目的, 為什麼有人會優先使用基于異常的模式, 而不是用行之有效的模式呢? 他們企圖利用Java的錯誤判斷機制來提高性能, 因為VM對每次數組通路都要檢查越界情況, 是以他們認為正常的循環終止測試被編譯器隐藏了, 但是在for-each循環中仍然可見, 這無疑是多餘的, 應該避免

  • 因為異常機制的設計初衷是用于不正常的情形, 是以很少會有JVM實作試圖對它們進行優化, 使得與先是的測試一樣快速
  • 把代碼放在try-catch塊中反而阻止了現代JVM實作本來可能執行的某些特定優化
  • 對數組進行周遊的标準模式并不會導緻備援的檢查, 有些現代的JVM實作會将它們優化掉

實際上, 在現代的JVM實作上, 基于異常的模式比标準模式要慢得多, 對于一個有100個元素的數組, 基于異常的模式比标準模式慢了2倍

58. 對可恢複的情況使用受檢異常, 對程式設計錯誤使用運作時異常

59. 避免不必要地使用受檢的異常

受檢的異常是Java程式設計語言的一項很好的特性, 與傳回代碼不同, 它們強迫程式員處理異常的條件, 大大增強了可靠性, 但是過分使用受檢的異常會使API使用起來非常不友善, 方法抛出多個受檢的異常, 就得在多個catch塊中處理這些異常, 異常的處理萬一又會出現異常, 是以這種情況要拆分代碼塊, 分解受檢的異常

60. 優先使用标準的異常

優先使用Java平台所提供的異常類

61. 抛出與抽象相對應的異常

當方法傳遞由低層抽象抛出的異常時, 往往會發生這種情況, 除了使人感到困惑之外, 這也讓實作細節污染了更高層的API, 如果高層的實作在後續的發行版本中發生了變化, 它所抛出的異常也可能會跟着發生變化, 進而潛在地破壞現有的用戶端程式, 為了避免這個問題, 更高的實作應該捕獲低層的異常, 同時抛出可以按照高層抽象進行解釋的異常

62. 每個方法抛出的異常都要有文檔

始終要單獨地壽命受檢的異常, 并且利用Javadoc的@throws标記, 準确地記錄下抛出每個異常的條件

63. 在細節消息中包含能捕獲失敗的資訊

為了捕獲失敗, 異常的細節資訊應該包含所有”對該異常有貢獻”的參數和域的值

64. 努力使失敗保持原子性

一般而言, 失敗的方法調用應該使對象保持在被調用之前的狀态, 具有這種屬性的方法被稱為具有失敗原子性

65. 不要忽略異常