java try-with-resources

在本教程中,我们将了解自动关闭资源的 try-with-resources 语句。

在本教程中,我们将了解自动关闭资源的 try-with-resources 语句。

try-with-resources 语句会在语句结束时自动关闭所有资源。能够自动关闭的资源是指实现了 AutoCloseable 接口的类。

try-with-resources 的语法是:

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

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

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

让我们举一个实现 try-with-resources 语句的例子。

示例 1:try-with-resources

import java.io.*;

public class Main {
  public static void main(String[] args) {
    try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
      System.out.println("进入了 try-with-resources 代码块");
      String line;
      while ((line = br.readLine()) != null) {
        System.out.println("Line => " + line);
      }
    } catch (IOException e) {
      System.out.println("try 代码块中的异常 =>" + e.getMessage());
    }
  }
}

如果未找到 test.txt 文件,则输出:

try 代码块中的异常 =>test.txt (系统找不到指定的文件。)

如果找到 test.txt 文件,则输出:

进入了 try-with-resources 代码块
Line => testline

在这个例子中,我们使用了一个 BufferedReader 实例从 test.txt 文件中读取数据。

try-with-resources 语句内声明和实例化 BufferedReader 实例对象确保最终被关闭,无论 try 语句是正常完成还是抛出异常。

使用 try-with-resources 的优点

以下是使用 try-with-resources 的优点:

  1. 不需要 finally 块关闭资源

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

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

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

    import java.io.*;
    
    public class Main {
      public static void main(String[] args) {
        BufferedReader br = null;
        String line;
    
        try {
          System.out.println("进入了 try 代码块");
          br = new BufferedReader(new FileReader("test.txt"));
          while ((line = br.readLine()) != null) {
            System.out.println("Line =>" + line);
          }
        } catch (IOException e) {
          System.out.println("try 代码块中的异常 =>" + e.getMessage());
        } finally {
          System.out.println("进入了 finally 代码块");
          try {
            if (br != null) {
              br.close();
            }
          } catch (IOException e) {
            System.out.println("IOException in finally block =>" + e.getMessage());
          }
        }
      }
    }
    

    输出

    进入了 try 代码块
    try 代码块中的异常 =>test.txt (系统找不到指定的文件。)
    进入了 finally 代码块

    从上面的例子我们可以看出,使用 finally 块来清理资源使得代码更加复杂。

    注意到 try...catch 块中的 finally 块了吗?因为在关闭 BufferedReader 实例时也可能发生 IOException 异常,因此也需要使用 try...catch 处理。

    try-with-resources 语句自动执行资源的清理工作,不需要我们显式关闭资源。这使代码更具可读性和更易于编写。

  2. try-with-resources 多资源

    我们可以在 try-with-resources 语句中声明多个资源,用分号 ; 分隔它们。

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

    import java.io.*;
    import java.util.*;
    public 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 语句在使用上有限制,资源必须在块本地声明。

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

如果我们在 Java 7 中在 try-with-resources 块外声明资源,它会生成一条错误消息。

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

为了处理这个错误,Java 9 改进了 try-with-resources 语句,这样即使资源的引用没有在本地声明,也可以使用。上面的代码在 Java 9 能正常执行编译和执行。

总结

以下是关于 try-with-resources 语句的知识要点:

  • try-with-resources 语句是 Java 7 开始加入的特性。
  • try-with-resources 语句可自动关闭资源。
  • try-with-resources 语句自动关闭的资源类型需要实现 AutoCloseable 接口。
  • try-with-resources 可支持声明多个资源。
  • try-with-resources 语句在 Java 9 以后可以使用在语句外声明的资源,Java 9 之前只能使用块内本地声明的资源。
  • try-with-resources 语句让代码更加简洁