💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# Java `try-with-resources` > 原文: [https://www.programiz.com/java-programming/try-with-resources](https://www.programiz.com/java-programming/try-with-resources) #### 在本教程中,我们将学习`try-with-resources`语句以自动关闭资源。 `try-with-resources`语句在语句末尾自动关闭所有资源。 资源是程序结束时要关闭的对象。 其语法为: ```java try (resource declaration) { // use of the resource } catch (ExceptionType e1) { // catch block } ``` 从上面的语法可以看出,我们通过以下方式声明`try-with-resources`语句: 1. 在`try`子句中声明和实例化资源。 2. 指定并处理关闭资源时可能引发的所有异常。 **注意**: `try-with-resources`语句关闭实现[`AutoCloseable`接口](https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html)的所有资源。 * * * 让我们以实现`try-with-resources`语句的示例为例。 ### 示例 1:`try-with-resources` ```java 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`文件,则输出。** ```java IOException in try-with-resources block =>test.txt (No such file or directory) ``` **如果找到`test.txt`文件,则输出。** ```java Entering try-with-resources block Line =>test line ``` 在此示例中,我们使用`BufferedReader`的实例从`test.txt`文件中读取数据。 在`try-with-resources`语句中声明并实例化`BufferedReader`可以确保无论`try`语句正常完成还是引发异常,都关闭其实例。 如果发生异常,则可以使用异常处理块或[`throws`关键字](https://www.programiz.com/java-programming/throw-throws)进行处理。 * * * ## 抑制的异常 在上面的示例中,在以下情况下,可以从`try-with-resources`语句引发异常: * 找不到文件`test.txt`。 * 关闭`BufferedReader`对象。 也可能从`try`块引发异常,因为文件读取可能随时因多种原因而失败。 如果从`try`块和`try-with-resources`语句都引发了异常,则将引发`try`块的异常并抑制来自`try-with-resources`语句的异常。 ### 检索抑制的异常 在 Java 7 和更高版本中,可以通过从`try`块引发的异常中调用`Throwable.getSuppressed()`方法来检索受抑制的异常。 此方法返回所有抑制的异常的数组。 我们在`catch`块中获得了抑制的异常。 ```java 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`的优势 这是使用`try-with-resources`的优点: ### 1.`finally`块不需要关闭资源 在 Java 7 引入此功能之前,我们必须使用`finally`块来确保关闭资源以避免资源泄漏。 这是一个类似于**示例 1** 的程序。 但是,在此程序中,我们使用了`finally`块来关闭资源。 ### 示例 2:使用`finally`块关闭资源 ```java import java.io.*; class Main { public static void main(String[] args) { BufferedReader br = null; String line; try { System.out.println("Entering try block"); 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("Entering finally block"); try { if (br != null) { br.close(); } } catch (IOException e) { System.out.println("IOException in finally block =>"+e.getMessage()); } } } } ``` **输出** ```java Entering try block Line =>line from test.txt file Entering finally block ``` 从上面的示例可以看出,使用`finally`块来清理资源使代码更加复杂。 注意`finally`块中的`try...catch`块吗? 这是因为在关闭`finally`块内的`BufferedReader`实例时也会出现`IOException`,因此也将其捕获并处理。 `try-with-resources`语句执行**自动资源管理**。 我们不需要显式关闭资源,因为 JVM 会自动关闭它们。 这使代码更具可读性,更易于编写。 * * * ### 2.`try-with-resources`和多种资源 我们可以用分号`;`分隔`try-with-resources`语句中的多个资源 ### 示例 3:`try-with-resources`和多种资源 ```java 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()); } } } } ``` 如果执行该程序时未生成任何异常,则`Scanner`对象将从`testRead.txt`文件中读取一行并将其写入新的`testWrite.txt`文件中。 进行多个声明时,`try-with-resources`语句以相反的顺序关闭这些资源。 在此示例中,首先关闭`PrintWriter`对象,然后关闭`Scanner`对象。 * * * ## Java 9 `try-with-resources`增强 在 Java 7 中,`try-with-resources`语句受到限制。 该资源需要在其块内本地声明。 ```java try (Scanner scanner = new Scanner(new File("testRead.txt"))) { // code } ``` 如果我们在 Java 7 中在块外声明资源,则将生成一条错误消息。 ```java Scanner scanner = new Scanner(new File("testRead.txt")); try (scanner) { // code } ``` 为了解决此错误,Java 9 改进了`try-with-resources`语句,以便即使未在本地声明资源引用也可以使用。 上面的代码现在将执行,没有任何编译错误。