在學習《Java try catch finally語句》一節後我們可以發現,當程序使用 finally 塊關閉資源時,程序會顯得異常臃腫,例如以下代碼。
public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("a.txt"); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } }}Java 7 以前,上面程序中的 finally 代碼塊是不得不寫的「臃腫代碼」,為了解決這種問題,Java 7 增加了一個新特性,該特性提供了另外一種管理資源的方式,這種方式能自動關閉文件,被稱為自動資源管理(Automatic Resource Management)。該特性是在 try 語句上的擴展,主要釋放不再需要的文件或其他資源。
自動資源管理替代了 finally 代碼塊,並優化了代碼結構和提高程序可讀性。語法如下:try (聲明或初始化資源語句) { } catch(Throwable e1){ } catch(Throwable e2){ } catch(Throwable eN){ }當 try 代碼塊結束時,自動釋放資源。不再需要顯式的調用 close() 方法,該形式也稱為「帶資源的 try 語句」。
注意:try 語句中聲明的資源被隱式聲明為 final,資源的作用局限於帶資源的 try 語句。
可以在一條 try 語句中聲明或初始化多個資源,每個資源以;隔開即可。
需要關閉的資源必須實現了 AutoCloseable 或 Closeable 接口。
Closeable 是 AutoCloseable 的子接口,Closeable 接口裡的 close() 方法聲明拋出了 IOException,因此它的實現類在實現 close() 方法時只能聲明拋出 IOException 或其子類;AutoCloseable 接口裡的 close() 方法聲明拋出了 Exception,因此它的實現類在實現 close() 方法時可以聲明拋出任何異常。
下面示範如何使用自動關閉資源的 try 語句。
public class AutoCloseTest { public static void main(String[] args) throws IOException { try ( BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java")); PrintStream ps = new PrintStream(new FileOutputStream("a.txt"))) { System.out.println(br.readLine()); ps.println("C語言中文網"); } }}上面程序中粗體字代碼分別聲明、初始化了兩個 IO 流,BufferedReader 和 PrintStream 都實現了 Closeable 接口,並在 try 語句中進行了聲明和初始化,所以 try 語句會自動關閉它們。
自動關閉資源的 try 語句相當於包含了隱式的 finally 塊(這個 finally 塊用於關閉資源),因此這個 try 語句可以既沒有 catch 塊,也沒有 finally 塊。Java 7 幾乎把所有的「資源類」(包括文件 IO 的各種類、JDBC 編程的 Connection 和 Statement 等接口)進行了改寫,改寫後的資源類都實現了 AutoCloseable 或 Closeable 接口。
如果程序需要,自動關閉資源的 try 語句後也可以帶多個 catch 塊和一個 finally 塊。
Java 9 再次增強了這種 try 語句。Java 9 不要求在 try 後的圓括號內聲明並創建資源,只需要自動關閉的資源有 final 修飾或者是有效的 final (effectively final),Java 9 允許將資源變量放在 try 後的圓括號內。上面程序在 Java 9 中可改寫為如下形式。public class AutoCloseTest { public static void main(String[] args) throws IOException { final BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java")); final PrintStream ps = new PrintStream(new FileOutputStream("a. txt")); try (br; ps) { System.out.println(br.readLine()); ps.println("C語言中文網"); } }}