開發者經常定義過多例外,把例外處理問題雪上加霜。

過度防禦的成因#

許多程式設計師被教導「應該偵測並回報錯誤」——但他們把這句話誤解為「偵測得越多越好」。

結果是過度防禦的程式風格:任何看起來有點可疑的東西都拋例外。

作者的反例:Tcl 的 unset#

作者本人在設計 Tcl 時也犯過:

  • unset 指令用來移除變數
  • 作者最初定義成:變數不存在 → 拋例外
  • 動機:他當時認為「刪一個不存在的變數」一定是 bug

但實際上:

  • unset 最常見的用途之一是「清理可能存在的暫存狀態
  • 中途中斷的操作可能留下未知數量的變數
  • 最簡單的做法就是把可能被建立的變數全部刪一遍
  • 結果是:開發者得在每個 unset 周圍包 catch,吞掉錯誤

作者回顧自己的設計:unset 這個定義是 Tcl 設計中最大的失誤之一

拋例外作為「逃避思考」#

很容易把例外當作避開困難的捷徑:

  • 不確定怎麼處理 → 直接拋給呼叫端
  • 表面論點:這樣讓呼叫端有彈性

但實際上:

都搞不清楚要怎麼處理,呼叫端多半也搞不清楚。

拋例外只是把問題推給別人,並讓系統更複雜。

例外是介面的一部分#

  • 一個類別會拋的例外屬於它的介面
  • 例外多 → 介面複雜 → 類別變淺
  • 例外又特別複雜,因為它沿著呼叫堆疊向上傳播:不只影響直接呼叫者,也影響更上層的方法(與其介面)

核心結論#

拋出例外容易,處理例外難。

例外的複雜性來自處理碼。

降低例外造成的複雜性損害,最好的方式是減少必須處理例外的位置數量

接下來四節會討論四種降低處理位置的技巧。