Nov. 07 16:23~17:45
圖片來源在此。打房有像Java SE 7 打壓exception那麼厲害就好了。
被打壓的例外
上一集提到在Java SE 7之後,可以用try-with-resource的方式讓JVM自動幫忙執行cleanup的工作。現在的問題是:如果JVM執行cleanup發生例外,這些cleanup例外要怎麼處理?Java SE 7的作法是,在Throwable類別身上多了一個Throwable[] getSuppressed() method,Suppressed是壓抑、抑制、打壓的意思。顧名思義,getSuppressed() method就是傳回「被抑制的例外」,也就是發生在執行cleanup動作所產生的例外。
請看以下程式片段,首先看到MyOutputStream類別,為了讓JVM可以自動關閉MyOutputStream所使用的資源,它實作了AutoCloseable介面。實作close() method的程式碼直接丟出一個IOException。
接著來使用用try-with-resources的方式來使用MyOutputStream類別。
在main()裡面來測試一下這個Java7TryWithResource() method,呼叫這個方法一定會產生一個IOException,從下列測試可以看出來捕捉到的IOException是由Java7TryWithResource()所丟出來的,還是MyOutputStream的close() method所丟出來的例外。
請參考下圖,答案揭曉,捕捉到的例外是由Java7TryWithResource() method所丟出來的那個IOException。MyOutputStream的close() method所丟出來的IOException變成了suppressed exception。
***
橋歸橋,路歸路(理論上)
這下子語意就比較清楚了,如果try-with-resources丟出例外,這個例外代表著function failure,如果例外還附帶有suppressed exception,則表示cleanup 失敗(廣義的來講,suppressed exception並不一定都表示cleanup 失敗)。捕捉到例外的人,除了要處理function failure,如果也想處理suppressed exception,則可以呼叫getSuppressed() method來逐一讀出每一個suppressed exception。
現在還剩下一個問題:如果try block或是catch block沒有丟出例外,而只有JVM在執行cleanup發生多的例外,那麼這些例外是由誰來壓制誰?也就是說呼叫者最後會收到哪一個例外?請參考下列程式片段:MyOutputStream、MyConnection、MyInputStream的close() method分別會丟出IOException、SQLException、FileNotFoundException。
在main()裡面測試一下Java7TryWithResources() method。
結果發現,被丟出來的例外是FileNotFoundException,而suppressed exception則是SQLException與IOException。也就是說,看起來JVM是依據使用資源的順序,反向的釋放這些資源(把資源物件依據宣告的順序,逐一放入堆疊之中,最後要執行cleanup動作再從堆疊裡面逐一拿出物件,並且呼叫這些物件的close() methods)。
***
細心一點的鄉民,看到這裡應該會發現一個問題:有了suppressed exception之後,雖然try block與catch block所丟出來的例外不會被cleanup例外給蓋台,但是例外的語意對捕捉到例外的人來講還是不夠清楚。如上圖所示,一個有suppressed exception的例外,可能是捕抓到try block或是catch block所丟出的例外,也可能是多個cleanup例外所組成。
怎麼辦?這算是一個例外類別設計的問題。下一集再來談一下這個問題。
***
友藏內心獨白:仔細讀,會讀出一點心得滴。
沒有留言:
張貼留言