📜  Java try-with-resources

📅  最后修改于: 2020-09-26 16:03:33             🧑  作者: Mango

在本教程中,我们将学习try-with-resources语句以自动关闭资源。

 

try-with-resources语句在语句末尾自动关闭所有资源。资源是程序结束时要关闭的对象。

其语法为:

try (resource declaration) {
  // use of the resource
} catch (ExceptionType e1) {
  // catch block
}

从上面的语法可以看出,我们通过以下方式声明try-with-resources语句,

  1. try子句中声明和实例化资源。
  2. 指定并处理关闭资源时可能引发的所有异常。

注意: try-with-resources语句关闭实现AutoCloseable接口的所有资源。


让我们以实现try-with-resources语句的示例为例。

示例1:尝试资源

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

在此示例中,我们使用BufferedReader的实例从test.txt文件读取数据。

try-with-resources语句中声明并实例化BufferedReader可以确保关闭其实例,而不管try语句是正常完成还是引发异常。

如果发生异常,则可以使用异常处理块或throws关键字对其进行处理。


禁止的异常

在上面的示例中,在以下情况下,可以从try-with-resources语句引发异常:

  • 找不到文件test.txt
  • 关闭BufferedReader对象。

也可以从try块中引发异常,因为文件读取可能随时因多种原因而失败。

如果try块和try-with-resources语句都抛出了异常,则try块的异常将被抛出, try-with-resources语句的异常被抑制。

检索抑制的异常

在Java 7和更高版本中,可以通过从try块引发的异常中调用Throwable.getSuppressed()方法来检索受抑制的异常。

此方法返回所有抑制的异常的数组。我们在catch块中得到了抑制的异常。

catch(IOException e) {
  System.out.println("Thrown exception=>" + e.getMessage());
  Throwable[] suppressedExceptions = e.getSuppressed();
  for (int i=0; i" + suppressedExceptions[i]);
  }
}

使用尝试资源的优势

 

这是使用try-with-resources的优点:

1.最终阻止不需要关闭资源

在Java 7引入此功能之前,我们必须使用finally块来确保关闭资源以避免资源泄漏。

这是一个类似于示例1的程序 。但是,在此程序中,我们使用了finally块来关闭资源。

示例2:使用finally块关闭资源

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());
      }

    }
  }
}

输出

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语句中声明多个资源,方法是用分号将它们分开;

示例3:尝试使用多种资源

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资源尝试功能增强

在Java 7中,对try-with-resources语句有一个限制。资源需要在其块内本地声明。

try (Scanner scanner = new Scanner(new File("testRead.txt"))) {
  // code
}

如果我们在Java 7中在块外部声明资源,则将生成一条错误消息。

Scanner scanner = new Scanner(new File("testRead.txt"));
try (scanner) {
  // code
}

为了解决此错误,Java 9改进了try-with-resources语句,以便即使未在本地声明资源的引用也可以使用。上面的代码现在将执行,没有任何编译错误。