# 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`语句，以便即使未在本地声明资源引用也可以使用。 上面的代码现在将执行，没有任何编译错误。