例外处理

*作:周思博(Joel Spolsky) *译:[天剑“Barabbas”姜姜天戬](/ wiki /用户:B6s“用户:B6s”)

有人问我为什么不喜欢写含有例外处理的程式。无论在Java或C ++里,我的原则都是:

1.绝不主动丢出例外状况。 2.总是在用到某函式库那行就逮住可能由它掷出的任何例外状况,并立刻解决。

理由是我不认为例外处理比“goto”好。“goto”自1960年 年代以来便[被视为是有害的(http://www.acm.org/classics/oct95/),因为它从程式码某处鲁莽地跳到另一处。事实上例外处理和 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夹杂在程式码里好多了。