Java類庫中包括許多必須經過調用close方法來手工關閉的資源。例如InputStream、OutputStream和java.sql.Connection。客戶端常常會忽略資源的關閉,形成嚴重的性能後果也就可想而知了。根據經驗,try-finally 語句是確保資源會被適當關閉的最佳方法,就算是發生異常或者返回也同樣:java
public String tryfinally(String path) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(new File(path))); try{ return reader.readLine(); }finally { reader.close(); } }
即使用 try-finally 語句正確地關閉了資源,它也存在着些許不足。由於在try塊和finally塊中的代碼,都會拋出異常。例如,底層的物理設備出現異常,那麼調用readLine就會拋出異常,基於一樣的緣由,調用close也會出現異常。在這種狀況下,第二個異常徹底抹除了第一個異常。在異常堆棧軌跡中,徹底沒有關於第一個異常的記錄,這在現實的系統中會致使調試變得很是複雜,由於一般須要看到第一個異常的記錄,這在現實的系統中會致使調試變得很是複雜,由於一般須要看到第一個異常才能診斷出問題何在。雖然能夠經過編寫代碼來禁止第二個異常,保留第一個異常,但事實上沒有人會這麼作,由於實現起來太繁瑣了。sql
如何完美解決這種問題呢?固然是Java7中引入的 try-with-resources 語句。編程
仍是上面的這段代碼,使用 try-with-resources 語句以後,新的代碼以下:性能
public String tryresources(String path) throws IOException { try(BufferedReader reader = new BufferedReader(new FileReader(new File(path)))){ return reader.readLine(); } }
使用這種 try-with-resources 不只使代碼變得簡潔易懂,也更容易進行診斷。以上段代碼爲例,若是調用 readLine 和 不可見的 close 方法都拋出異常,後一個異常就會被禁止,以保留第一個異常。事實上,爲了保留你想看到的那個異常,即使多個異常均可以被禁止。這些被禁止的異常並非簡單地被拋棄了,而是會被打印在堆棧軌跡中,並註明它們是被禁止的異常。經過編程調用 getSuppressed 方法還能夠訪問到它們,getSuppressed 方法也已經添加在Java7的Throwable中了。調試
使用 try-with-resources 語句有什麼要求嗎?code
是的,要使用這個構造的資源,必須先實現 AutoCloseable 接口,其中包含了單個返回 void 的 close 方法。Java類庫與第三方類庫中的許多類和接口,如今都實現或擴展了 AutoCloseable 接口。接口
public interface AutoCloseable { void close() throws Exception; }
如下是使用 try-with-resources 的第二個範例:資源
void tryresources(String src,String dst) throws IOException { try(InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst)){ byte[] bytes = new byte[1024]; int n; while ((n=in.read(bytes))>=0){ out.write(bytes,0,n); } } }
在 try-with-resources 語句中還可使用 catch 子句,就像在平時的 try-finally 語句中同樣。get
public String tryresources(String path){ try(BufferedReader reader = new BufferedReader(new FileReader(new File(path)))){ return reader.readLine(); } catch (IOException e) { return null; } }
有了 try-with-resources 語句,在使用必須關閉的資源時,就能更輕鬆地正確編寫代碼了。it