在本教程中,我們將學(xué)習(xí)try-with-resources語(yǔ)句以自動(dòng)關(guān)閉資源。
try-with-resources語(yǔ)句在語(yǔ)句末尾自動(dòng)關(guān)閉所有資源。資源是程序結(jié)束時(shí)要關(guān)閉的對(duì)象。
其語(yǔ)法為:
try (resource declaration) { // use of the resource } catch (ExceptionType e1) { // catch block }
從上面的語(yǔ)法可以看出,我們通過以下方式聲明try-with-resources語(yǔ)句:
在try子句中聲明和實(shí)例化資源。
指定并處理關(guān)閉資源時(shí)可能引發(fā)的所有異常。
注意:try-with-resources語(yǔ)句關(guān)閉實(shí)現(xiàn)AutoCloseable接口的所有資源。
讓我們以實(shí)現(xiàn)try-with-resources語(yǔ)句的示例為例。
import java.io.*; class Main { public static void main(String[] args) { String line; try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) { while ((line = br.readLine()) != null) { System.out.println("Line =>"+line); } } catch (IOException e) { System.out.println("IOException in try block =>" + e.getMessage()); } } }
如果找不到test.txt文件,則輸出。
IOException in try-with-resources block =>test.txt (No such file or directory)
如果找到了test.txt文件,則輸出。
Entering try-with-resources block Line =>test line
在此示例中,我們使用的實(shí)例BufferedReader從test.txt文件中讀取數(shù)據(jù)。
在try-with-resources語(yǔ)句中聲明并實(shí)例化BufferedReader可以確保關(guān)閉其實(shí)例,而不管try語(yǔ)句是正常完成還是引發(fā)異常。
如果發(fā)生異常,則可以使用異常處理塊或throws關(guān)鍵字對(duì)其進(jìn)行處理。
在上面的示例中,在以下情況下可以從try-with-resources語(yǔ)句引發(fā)異常:
找不到test.txt文件。
關(guān)閉BufferedReader對(duì)象。
也可以從try塊中引發(fā)異常,因?yàn)槲募x取可能隨時(shí)因多種原因而失敗。
如果從try塊和try-with-resources語(yǔ)句都拋出異常,則會(huì)拋出try塊中的異常,并抑制try-with-resources語(yǔ)句中的異常。
在Java 7和更高版本中,可以通過Throwable.getSuppressed()從try塊引發(fā)的異常中調(diào)用方法來檢索抑制的異常。
此方法返回所有抑制的異常的數(shù)組。我們?cè)赾atch塊中得到了抑制的異常。
catch(IOException e) { System.out.println("Thrown exception=>" + e.getMessage()); Throwable[] suppressedExceptions = e.getSuppressed(); for (int i=0; i<suppressedExceptions.length; i++) { System.out.println("Suppressed exception=>" + suppressedExceptions[i]); } }
這是使用try-with-resources的優(yōu)點(diǎn):
在Java 7引入此功能之前,我們必須使用該finally塊來確保關(guān)閉資源以避免資源泄漏。
這是一個(gè)類似于示例1的程序。但是,在此程序中,我們使用了finally塊來關(guān)閉資源。
import java.io.*; class Main { public static void main(String[] args) { BufferedReader br = null; String line; try { System.out.println("進(jìn)入try 塊"); br = new BufferedReader(new FileReader("test.txt")); while ((line = br.readLine()) != null) { System.out.println("Line =>"+line); } } catch (IOException e) { System.out.println("IOException in try block =>" + e.getMessage()); } finally { System.out.println("進(jìn)入 finally 塊"); try { if (br != null) { br.close(); } } catch (IOException e) { System.out.println("IOException in finally block =>"+e.getMessage()); } } } }
輸出結(jié)果
進(jìn)入try 塊 Line =>line from test.txt file 進(jìn)入 finally 塊
從上面的示例可以看出,使用finally塊來清理資源使代碼更加復(fù)雜。
您注意到finally塊中的try ... catch塊嗎? 這是因?yàn)樵陉P(guān)閉此finally塊內(nèi)的BufferedReader實(shí)例時(shí)也可能發(fā)生IOException,因此也將其捕獲并處理。
try-with-resources語(yǔ)句執(zhí)行自動(dòng)資源管理。我們不需要顯式關(guān)閉資源,因?yàn)镴VM會(huì)自動(dòng)關(guān)閉它們。這使代碼更具可讀性,更易于編寫。
我們可以try-with-resources使用分號(hào)將多個(gè)資源分開,從而在語(yǔ)句中聲明多個(gè)資源;
import java.io.*; import java.util.*; class Main { public static void main(String[] args) throws IOException{ try (Scanner scanner = new Scanner(new File("testRead.txt")); PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) { while (scanner.hasNext()) { writer.print(scanner.nextLine()); } } } }
如果執(zhí)行該程序時(shí)未生成任何異常,則Scannerobject從testRead.txt文件中讀取一行并將其寫入新testWrite.txt文件中。
進(jìn)行多個(gè)聲明時(shí),try-with-resources語(yǔ)句以相反的順序關(guān)閉這些資源。在此示例中,首先關(guān)閉PrintWriter對(duì)象,然后關(guān)閉Scanner對(duì)象。
在Java 7中,該try-with-resources語(yǔ)句有一個(gè)限制。該資源需要在其塊內(nèi)本地聲明。
try (Scanner scanner = new Scanner(new File("testRead.txt"))) { // code }
如果我們?cè)贘ava 7中在塊外部聲明資源,則將拋出錯(cuò)誤消息。
Scanner scanner = new Scanner(new File("testRead.txt")); try (scanner) { // code }
為了解決此錯(cuò)誤,Java 9 改進(jìn)了該try-with-resources語(yǔ)句,以便即使未在本地聲明資源引用也可以使用。上面的代碼現(xiàn)在將執(zhí)行,不會(huì)拋出任何編譯錯(cuò)誤。