l

2013年11月19日 星期二

Java的try、catch、finally(5):表達清楚的Cleanup Failure語意

Nov. 07 22:36~23:36

image

語意不清,如同雞同鴨講。

 

在上一集中提到cleanup failure的語意在Java SE 7新增try-with-resources敘述之後依舊還是不太清楚,為了解決這個問題,Teddy提出一個建議作法給鄉民們參考一下。

***

定義Cleanup Failure語意

這個問題的根本原因就是Java語言內建的例外沒有一個是用來表示cleanup failure,因此鄉民們自行定義一個CleanupException用來代表cleanup failure,如下圖所示。

螢幕快照 2013-11-07 下午10.42.27

 

CleanupException繼承自RuntimeExceptioin,是一個unchecked exception。為什麼不是checked exception?原因有二:

  • 因為只要是需要釋放資源的地方都可以會丟出CleanupException,Teddy之前有提到,從例外處理者的角度來看,主要關注的是function failure,如果把CleanupException設計成checked exception,則會強迫例外處理者隨時都要關注這個比較次要的例外狀況,最後可能會導致這個例外反射性地被忽略,產生Ignored Checked Exception這個例外處理的壞味道。
  • 再者,cleanup會失敗,可能是design fault(bug)也可能是component fault(和其他元件互動時因為別人出問題所產生的錯誤)。「理論上」,cleanup的動作應該要儘量可靠,否則系統不是三不五時就產生memory leak。實務上,Teddy在呼叫Java系統內建的close() method也鮮少發生例外。既然發生cleanup failure的機率很低,把CleanupException設計成runtime exception,姑且當作design fault來看待。當應用程式真正被測試或使用的時候,如果真的有發生CleanupException,這個例外會被系統最上層的主程式給寫到日誌檔當中。此時開發人員有一個比較具體的context或是scenario,可以來研究如何排除這個CleanupException。

***

修改close() method丟出的例外

有了CleanupException之後,接下來的事情就好辦了。原本的MyConnection、MyInputStream、MyOutputStream這三個類別的close() method,分別丟出SQLException、FileNotFoundException()、IOException,把這些不同型別的例外全部改成CleanupException。

螢幕快照 2013-11-07 下午10.58.46

螢幕快照 2013-11-07 下午10.59.00

螢幕快照 2013-11-07 下午10.59.12

 

如下三圖所示,雖然三個不同資源類別的close() method都是丟出CleanupException,但是原本產生的例外物件:SQLException、FileNotFoundException、IOException,還是被串接在CleanupException身上。也就是說,例外處理程式還是可以從CleanupException身上知道當初引發CleanupException的原因。

螢幕快照 2013-11-07 下午11.02.19

螢幕快照 2013-11-07 下午11.02.32

螢幕快照 2013-11-07 下午11.02.45

***

Cleanup Failure的語意清楚了嗎?

接下來看兩個例子,就可以知道cleanup failure語意是否清楚了。首先,在try-with-resources裡面使用MyOutputStream、MyConnection、MyInputStream這三個資源物件。然後在try block故意丟出一個IOException。

螢幕快照 2013-11-07 下午11.13.31

 

在main()程式中呼叫tryWithRessourcesThrowFailureException() method。

螢幕快照 2013-11-07 下午11.16.11

 

被捕捉到的是由try block所丟出的failure exception,並且夾帶著三個suppressed exception,型態都是CleanupException。正如剛剛的設計,而這三個CleanupException分別由FileNotFoundException、SQLException、IOException所引起。

螢幕快照 2013-11-07 下午11.17.41

***

接著再看原本會引起cleanup failure語意不清的例子,就是try block裡面沒有丟出例外,但是JVM呼叫close() method時會發生例外。

螢幕快照 2013-11-07 下午11.21.12

 

在main()程式中呼叫tryWithRessourcesThrowCleanupException() method。

螢幕快照 2013-11-07 下午11.23.06

 

結果完全符合設計的預期,被捕捉到的例外是CleanupExceptioin,它夾帶另外兩個suppressed exception,型態都是CleanupException。而這三個CleanupException分別由FileNotFoundException、SQLException、IOException所引起。

螢幕快照 2013-11-07 下午11.24.04

***

看到這裡如果鄉民們還沒跑走的話,應該就可以很清楚的看出來function failure和cleanup failure的語意都非常清楚的區分出來。這樣子不但有助於例外處理程式的設計,對於日後加速除錯的進行也很有幫助。

但是,眼尖的人應該還是會發現一個問題:可是Java語言內建的資源物件,它們實作AutoCloseable介面的close() method的時候,丟出來的都不是CleanupException啊?Teddy認為這的確是一個Java例外處理設計的問題。有沒有解?請看下回分曉。

***

友藏內心獨白:這裡面還是有點學問滴。

沒有留言:

張貼留言