Java IO: 異常處理
原文連結 作者:Jakob Jenkov 譯者: 李璟([email protected])
流與Reader和Writer在結束使用的時候,需要正確地關閉它們。通過呼叫close()方法可以達到這一點。不過這需要一些思考。請看下邊的程式碼:
InputStream input = new FileInputStream("c:\\data\\input-text.txt"); int data = input.read(); while(data != -1) { //do something with data... doSomethingWithData(data); data = input.read(); } input.close();
第一眼看這段程式碼時,可能覺得沒什麼問題。可是如果在呼叫doSomethingWithData()方法時出現了異常,會發生什麼呢?沒錯,這個InputStream物件就不會被關閉。
為了避免異常造成流無法被關閉,我們可以把程式碼重寫成這樣:
InputStream input = null; try{ input = new FileInputStream("c:\\data\\input-text.txt"); int data = input.read(); while(data != -1) { //do something with data... doSomethingWithData(data); data = input.read(); } }catch(IOException e){ //do something with e... log, perhaps rethrow etc. } finally { if(input != null) input.close(); }
注意到這裡把InputStream的關閉程式碼放到了finally塊中,無論在try-catch塊中發生了什麼,finally內的程式碼始終會被執行,所以這個InputStream總是會被關閉。
但是如果close()方法丟擲了異常,告訴你流已經被關閉過了呢?為了解決這個難題,你也需要把close()方法寫在try-catch內部,就像這樣:
} finally { try{ if(input != null) input.close(); } catch(IOException e){ //do something, or ignore. } }
這段解決了InputStream(或者OutputStream)流關閉的問題的程式碼,確實是有一些不優雅,儘管能夠正確處理異常。如果你的程式碼中重複地遍佈了這段醜陋的異常處理程式碼,這不是很好的一個解決方案。如果一個匆忙的傢伙貪圖方便忽略了異常處理呢?
此外,想象一下某個異常最先從doSomethingWithData方法內丟擲。第一個catch會捕獲到異常,然後在finally里程序會嘗試關閉InputStream。但是如果還有異常從close()方法內丟擲呢?這兩個異常中得哪個異常應當往呼叫棧上傳播呢?
幸運的是,有一個辦法能夠解決這個問題。這個解決方案稱作“異常處理模板”。建立一個正確關閉流的模板,能夠在程式碼中做到一次編寫,重複使用,既優雅又簡單。詳情參見Java異常處理模板。
Java7中IO的異常處理
從Java7開始,一種新的被稱作“try-with-resource”的異常處理機制被引入進來。這種機制旨在解決針對InputStream和OutputStream這類在使用完畢之後需要關閉的資源的異常處理。可以瀏覽Try with Resource in Java 7獲得更多資訊。