例外處理 Exceptions

作:周思博 (Joel Spolsky)
譯:Tian-Jian "Barabbas" Jiang 姜天戩
屬於 Joel on Software, https://www.joelonsoftware.com/2003/10/13/13/

有人問我為什麼不喜歡寫含有例外處理的程式。無論在 Java 或 C++ 裡,我的原則都是:

  1. 絕不主動丟出例外狀況。
  2. 總是在用到某函式庫那行就逮住可能由它擲出的任何例外狀況,並立刻解決。

理由是我不認為例外處理比 "goto" 好。"goto" 自 1960 年代以來便被視為是有害的,因為它從程式碼某處魯莽地跳到另一處。事實上例外處理和 goto 比起來有更重大的缺陷:

  1. 例外處理在原始碼中是隱形的。檢閱一段程式,無論函式會不會拋出例外狀況,都沒辦法看出例外狀況可能是什麼或發生在那裡。這表示即使小心核對程式碼也糾不出潛在的 bug。
  2. 例外處理在函式裡產生了太多出口。想寫好程式,你得想清楚函式裡每個可能的步驟。每次你呼叫某個可能引發例外狀況的函式又沒能當機立斷,你就替意料之外的 bug 製造了硬生生地終結函式的機會,而使資料陷於不一致的狀態下或跑到你沒想到的程序裡。

比較可取的方法是在函式出問題時回報錯誤,那怕它會有些冗贅,也要明確地處理。的確,當你在程式裡加入良好的錯誤檢驗時,原來簡短三行的程式常會膨脹到 48 行,但人生不如意事十之八九,況且用例外處理粉飾程式並不會讓它更強韌。我想 C / C++ / Java 式語言的程式設計師會被例外處理吸引的理由,只是單純地因為文法規則裡沒有簡潔的方式能叫用傳回多重數值的函式,所以產生回傳值或回報錯誤的函式寫起來不容易。(ML 和 Haskell 是我常用的程式語言裡少數能巧妙地傳回多值的語言。)在 C / C++ / Java 式語言裡有一招可以用來處理錯誤,就是以實際回傳數值代表結果的狀態,同時如果有想要傳回的東西,就傳入 OUT 參數來存取。這樣的作法有個令人遺憾的副作用是無法層層呼叫函式,於是 f(g(x)) 的答案得改成:

T tmp;
if (ERROR == g(x, tmp))
    errorhandling;
if (ERROR == f(tmp, result))
    errorhandling;

這樣又醜又麻煩,但比無法預期的部分帶著詭異的 goto 夾雜在程式碼裡好多了。

這些網頁的內容為表達個人意見。
All contents Copyright © 1999-2006 by Joel Spolsky. All Rights Reserved.