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
语句的例子。
示例 1: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的优点
以下是使用try-with-resources的优点:
1. finally块无需关闭资源
在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与多个资源
我们可以通过用分号;
分隔来在try-with-resources
语句中声明多个资源。
示例 3:try与多个资源
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
语句存在一个限制。资源需要在其块内本地声明。
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
语句,以便即使资源未在本地声明,也可以使用其引用。上面的代码现在可以成功编译执行。