l

2011年5月30日 星期一

Checked or unchecked exceptions (1)

May 30 20:46~22:12

Java 語言將 exceptions 分成兩種:checked exceptions and unchecked exceptions(備註:unchecked exceptions 又稱為 runtime exceptions)。 鄉民們可能會對這兩個分類的命名覺的有點奇怪,為什麼要叫做 checked, unchecked?簡單的說, checked or unchecked 是從 Java compiler 的角度來看 exceptions,如果你有一個 method M 長成下面這個樣子:

public void M() {

  throw mew MyException();

}

從上面這段 source code 中,鄉民們可以看到 M() 會丟出 MyException 這個例外,如果 MyException 是屬於 checked exceptions 這個分類,那麼 Java compiler 會很雞婆的幫鄉民們『檢查』下面這件事:

如果 M() 沒有去『捕捉』MyException,那麼 MyException 就一定要被宣告在 M() 的 signature 中。

以上就是所謂的 handle-or-declare rule,如果 MyException 是一個 checked exception,上面這的程式要改成下面這樣子才可以被 Java compiler 成功編譯。

// 符合 handle 的要求
public void M() {

 try {

      throw mew MyException();

 }
  catch (MyException e) {

     // do something
  }

}




// 符合 declare 的要求
public void M() throws MyException{

  throw mew MyException();

}
 
在程式中如果有人丟出 checked exceptions 這種分類的例外,Java compiler 會去檢查 handle-or-declare rule 有沒有被遵守,如果沒有,就視為『語法錯誤』,程式是無法編譯成功的。對於 unchecked exceptions 這種分類的例外,Java compiler 是不會鳥他的,隨便鄉民們愛怎麼丟,就怎麼丟。

***

現在問題來了,Java 吃飽沒事幹為什麼要把 exceptions 分成這兩種類型,然後又要求 Java compiler 去『檢查』當鄉民們使用 checked exceptions 時有沒有『乖乖的遵守交通規則』?講到這邊又是一言難盡,請參考這本書 Effective Java, 2nd, Chapter 9: Exceptions. Teddy 把這一章的內容列出來給鄉民們參考一下,答案就在 Item 58 之中:

  • Item 57: Use exceptions only for exceptional conditions.
  • Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.
  • Item 59: Avoid unnecessary use of checked exceptions.
  • Favor the use of standard exceptions.
  • Throw exceptions appropriate to the abstraction.
  • Document all exceptions thrown by each method.
  • Include failure-capture information in detail messages.
  • Strive for failure atomicity.
  • Don't ignore exception.
Java 是第一個採用 checked exceptions 而且被廣泛使用的程式語言(以前都只有 unchecked exceptions),Java 的設計者認為,unchecked exceptions 很容易被 programmers 給忽略,導致例外沒有被處理而降低的系統的強健度(robustness)。所以就在 Java 語言中提出了 checked exceptions 這種分類並且讓 compiler 幫  programmers 去檢查,如果程式中發生  checked exceptions 的話,那麼一定要提高警覺,要給這個 checked exceptions『關愛的眼神』,千萬不要不理它啊(最基本的門檻就是程式碼要符合 handle-or-declare rule)。

此外,Java 設計者還給 checked 和  unchecked exceptions 附加了不同的『語意』,也就是上面 item 58 所說的:
  • Checked exceptions for recoverable conditions.
  • Runtime (unchecked) exceptions for programming errors.
上面這兩點非常重要,在 Java 程式中做例外處理,不是只會寫程式就好了,還要和 Java 設計者『心心相印』。Java 的設計者認為,checked exceptions 本質上代表著一種『可以被修復的例外狀況』,因此,當鄉民們遇到 checked exceptions,『理當』去 handle 它,為什麼?因為既然 checked exceptions 代表『recoverable conditions』,那麼就想辦法去 recover 啊(東西壞掉總不能不修理就直接丟掉換新的吧...XD)。

Unchecked exceptions 則表示 programming errors,翻成白話文就是說如果鄉民們遇到一個 unchecked exceptions 則表示程式中有 bug。那麼 unchecked exceptions 要如何『處理(handle)』呢?

把上面這個問題換成這個問句答案就很清楚了:程式有 bugs  要如何處理?答案很簡單啊,有  bugs 就改程式把 bugs 修掉啊。對,所以,unchecked exceptions 『理論上不應該在程式中去 handle 它』,因為它代表 bugs,所以當 unchecked exceptions 發生時只要在 main method 中 catch 並且 report 給 end-users or programmers 便可。
 
***

Checked or unchecked exceptions 的故事還很長,雖然 Java 的設計者希望鄉民們能夠瞭他們的想法,但是也有很多人是不買帳的。理想歸理想,實際上寫程式的時候會遇到以下問題:
  • 雖說 checked exceptions for recoverable conditions,但是為什麼偏偏當程式中遇到一個 checked exception 的時候鄉民們卻打死也不知道要如何去 recover 任何東東?舉個最常見的 checked exception, IOException,為例,處理檔案,stream,socket 都會『附贈』IOException,收到這份大禮之後該怎麼辦?沒人知道。
  • 既然 checked exceptions 要符合 handle-or-declare rule,但是鄉民們既不知道如何 handle,也不明白如何 declare。Exceptions 這麼多,怎麼處理?那就亂處理啊!所以程式中經常可以看到 catch and ignore (exceptions 被捕捉且被忽略)或是 blindly declare (盲目地將所有發生的 checked exceptions 都宣告在 method 上面繼續往外丟)。
  • Checked exceptions 要宣告在 method 的 signature 上,所以如果一個  method 會丟出去的 checked exceptions 數目或是 type 改變了,那個這個 method 的 signature 也變了,就等於 interface 也變了。改變介面這件事可不是好玩滴...
  • 有些鄉民們『不遵教化』,打死都不想用 checked exceptions。問題是這些鄉民們又沒事寫出很多很好用的 open source 軟體,那麼當我們使用這些軟體的時候,就開始『神經錯亂』了。原本 Java 告訴大家,unchecked exceptions 代表 bugs,不用去 handle,但是不甩這一套的人只用 unchecked exceptions,也就是說這些人也用 unchecked exceptions 來代表 recoverable conditions 與 programming errors。那那那.......『民安手措其手足』?

Checked or unchecked exceptions 第一集講完,預知結果請看下回分曉。

 ***

友藏內心獨白:留言說例外處理很難搞的這位『匿名 』人士,你沒看 Teddy 的這篇 paper 喔:Exception Handling Refactorings: Directed by Goals and Driven by Bug Fixing

2 則留言:

  1. exception management 是很難練心法,謝謝分享!

    回覆刪除
  2. To chliu:

    歡迎批評指教,有寫錯的地方還請指正。

    回覆刪除