對於資源的擷取和關閉,如檔案,JDBC,需要程式員手動關閉資源,如close,shutdown等。如果關閉資源不當,就會發生資源流失。
例子1:
public static Properties loadPropertiesBadly(String fileName) throws IOException { FileInputStream stream = new FileInputStream(fileName); Properties props = new Properties(); props.load(stream); stream.close(); return props; } 幸的是,這個例子存在潛在的資源泄漏。如果一切進展順利,流將會在方法返回之前被關閉。但是如果 props.load() 方法拋出一個 IOException ,那麼流則不會被關閉(直到垃圾收集器運行其終結器)。解決方案是使用 try...finally 機制來確保流被關閉,而不管是否發生錯誤。
例子2:
public static Properties loadProperties(String fileName) throws IOException { FileInputStream stream = new FileInputStream(fileName); try { Properties props = new Properties(); props.load(stream); return props; } finally { stream.close(); } } 注意,資源擷取(開啟檔案)是在 try 塊外面進行的;如果把它放在 try 塊中,那麼即使資源擷取拋出異常,finally 塊也會運行。不僅該方法會不適當(您無法釋放您沒有擷取的資源),finally 塊中的代碼也可能拋出其自己的異常,比如 NullPointerException 。從 finally 塊拋出的異常取代導致塊退出的異常,這意味著原來的異常丟失了,不能用於協助進行調試。
例子3:
public void enumerateFoo() throws SQLException { Statement statement = null; ResultSet resultSet = null; Connection connection = getConnection(); try { statement = connection.createStatement(); resultSet = statement.executeQuery("SELECT * FROM Foo"); // Use resultSet } finally { if (resultSet != null) resultSet.close(); if (statement != null) statement.close(); connection.close(); } } 這個 “解決方案” 不成功的原因在於, ResultSet 和 Statement 的 close() 方法自己可以拋出 SQLException ,這會導致後面 finally 塊中的 close() 語句不執行。您在這裡有幾種選擇,每一種都很煩人:用一個 try..catch 塊封裝每一個 close() ,像清單 4 那樣嵌套 try...finally 塊,或者編寫某種小型架構用於管理資源擷取和釋放