原文: https://www.programiz.com/java-programming/try-with-resources
try-with-resources语句在语句末尾自动关闭所有资源。 资源是程序结束时要关闭的对象。
其语法为:
try (resource declaration) {
// use of the resource
} catch (ExceptionType e1) {
// catch block
} 从上面的语法可以看出,我们通过以下方式声明try-with-resources语句:
- 在
try子句中声明和实例化资源。 - 指定并处理关闭资源时可能引发的所有异常。
注意: try-with-resources语句关闭实现AutoCloseable接口的所有资源。
让我们以实现try-with-resources语句的示例为例。
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.length; i++) {
System.out.println("Suppressed exception=>" + suppressedExceptions[i]);
}
} 这是使用try-with-resources的优点:
在 Java 7 引入此功能之前,我们必须使用finally块来确保关闭资源以避免资源泄漏。
这是一个类似于示例 1 的程序。 但是,在此程序中,我们使用了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 会自动关闭它们。 这使代码更具可读性,更易于编写。
我们可以用分号;分隔try-with-resources语句中的多个资源
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 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语句,以便即使未在本地声明资源引用也可以使用。 上面的代码现在将执行,没有任何编译错误。