高效Java:丟擲適合抽象的異常 - Kyle Carter

banq發表於2021-08-25

《Effective Java》一書的大部分內容都是聚焦構建一個乾淨、易懂的 API 以及它如何成為一個偉大庫的基礎。類的 API 的一部分是任何異常,它可能會丟擲已檢查(它成為簽名的一部分)或未檢查的堆疊。作為程式碼的編寫者,我們有責任確保此 API 不會出現任何意外或令人震驚的情況。發生這種情況的一種方式是暴露一個對我們正在編寫的類沒有意義的異常。
不匹配異常的一個潛在示例是,如果您請求將兩個數字相加時,方法丟擲一個IOException. 透過丟擲這個低階異常,你將實現細節暴露給呼叫者,實現細節在未來可能會改變,但現在它是你的 API 的一部分,因此很難改變。那麼有什麼方法可以解決這個問題呢?
用於解決此問題的主要方法是執行所謂的異常轉換。異常轉換是當您捕獲較低階別的異常並將其包裝在與您正在處理的抽象相匹配的較高階別的異常中時。

public E get(int index) {
  ListIterator<E> = listIterator(index);
  try {
    return i.next();
  } catch (NoSuchElementException e) {
    throw new IndexOutOfBoundsException("Index: " + index);
  }
}

這裡將
NoSuchElementException 
異常轉為IndexOutOfBoundsException丟擲。
 
上面是將較低階別的異常包裝在較高階別的異常中,但也將較低階別的異常作為原因傳遞給較高階別的異常。許多方法公開此原因欄位,並將其傳遞給 Throwable 類。
更重要的是,這個原因是透過堆疊跟蹤暴露出來的,這可以極大地幫助除錯問題。這確實間接地向呼叫方法公開了較低階別的詳細資訊。然而,它並沒有很直接地完成它,因此它不會強制呼叫者處理低階異常,相反,他們仍然可以處理高階異常,而不必擔心低階實現細節。
 
最容易處理的異常是不會被丟擲的異常。我們應該始終努力在我們的所有程式碼中不丟擲可避免的異常。Effective Java有時甚至建議我們可以解決異常並簡單地記錄它們並繼續前進。不過,我會警告不要使用這種模式。如果我們只是在特殊情況下丟擲異常,那麼呼叫者可能需要知道發生了一些事情,並且簡單地將其隱藏在呼叫者面前可能會出現問題。




 

相關文章