開發者經常定義過多例外,把例外處理問題雪上加霜。
過度防禦的成因#
許多程式設計師被教導「應該偵測並回報錯誤」——但他們把這句話誤解為「偵測得越多越好」。
結果是過度防禦的程式風格:任何看起來有點可疑的東西都拋例外。
作者的反例:Tcl 的 unset#
作者本人在設計 Tcl 時也犯過:
unset指令用來移除變數- 作者最初定義成:變數不存在 → 拋例外
- 動機:他當時認為「刪一個不存在的變數」一定是 bug
但實際上:
unset最常見的用途之一是「清理可能存在的暫存狀態」- 中途中斷的操作可能留下未知數量的變數
- 最簡單的做法就是把可能被建立的變數全部刪一遍
- 結果是:開發者得在每個
unset周圍包catch,吞掉錯誤
作者回顧自己的設計:
unset這個定義是 Tcl 設計中最大的失誤之一。
拋例外作為「逃避思考」#
很容易把例外當作避開困難的捷徑:
- 不確定怎麼處理 → 直接拋給呼叫端
- 表面論點:這樣讓呼叫端有彈性
但實際上:
若你都搞不清楚要怎麼處理,呼叫端多半也搞不清楚。
拋例外只是把問題推給別人,並讓系統更複雜。
例外是介面的一部分#
- 一個類別會拋的例外屬於它的介面
- 例外多 → 介面複雜 → 類別變淺
- 例外又特別複雜,因為它沿著呼叫堆疊向上傳播:不只影響直接呼叫者,也影響更上層的方法(與其介面)
核心結論#
拋出例外容易,處理例外難。
例外的複雜性來自處理碼。
降低例外造成的複雜性損害,最好的方式是減少必須處理例外的位置數量。
接下來四節會討論四種降低處理位置的技巧。