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 和 unchecked exceptions 附加了不同的『語意』,也就是上面 item 58 所說的:
- Checked exceptions for recoverable conditions.
- Runtime (unchecked) exceptions for programming errors.
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 。
exception management 是很難練心法,謝謝分享!
回覆刪除To chliu:
回覆刪除歡迎批評指教,有寫錯的地方還請指正。