在下面的代码块中:
try ( /* resources declaration */ ) {
// some dangerous code
} catch (Exception e) {
// error handling and reporting
}
如果 try
块中的代码和自动 close()
语句都引发异常,会发生什么情况?哪一个会被困在catch
块中?他们两个?只有一个?如果是,是哪一个?
此外,如果try
成功但close
不成功怎么办?会输入捕获块吗?
JLS第14.20.3.1节:
在管理单个资源的基本 try-with-resources 语句中:
- 如果资源的初始化由于值
V
throw
而突然完成,则 try-with-resources 语句会因为值V
throw
而突然完成。如果资源的初始化正常完成,并且
try
块由于值V
的throw
而突然完成,则:
如果资源的自动关闭正常完成,则 try-with-resources 语句会因为值
V
throw
而突然完成。如果资源的自动关闭由于值
V2
的throw
而突然完成,则 try-with-resources 语句会突然完成,因为throw
的值V
V2
添加到禁止的异常列表中V
。- 如果资源的初始化正常完成,
try
块正常完成,并且资源的自动关闭因为抛出一个值V
而突然完成,则 try-with-resources 语句会因为值V
throw
而突然完成。
这意味着,如果 try
块中的代码和自动 close()
语句都抛出异常,则 catch
部分将处理 try
块引发的异常,而抑制异常中close()
抛出的异常。
此外,这意味着如果try
块成功但自动close()
失败,则catch
将被执行,捕获的异常将是close()
抛出的异常。
下面是验证此行为的测试:
public class Main {
public static void main(String[] args) throws Exception {
// try block fails and close() fails
try (T t = new T()) {
throw new Exception("thrown by try part");
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.getSuppressed()[0].getMessage());
}
// try block is successful but close() fails
try (T t = new T()) {
//
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
class T implements AutoCloseable {
@Override
public void close() throws Exception {
throw new Exception("thrown by close");
}
}
此代码将打印
thrown by try part
thrown by close
thrown by close
这意味着捕获的异常是第一部分代码的 try 部分引发的异常。对于第二部分,捕获的异常确实是close()
抛出的异常。
try 块内抛出的异常被抛出到外部世界。
而使用 try-catch-finally 时,从 finally 块抛出的异常将沿调用堆栈向上传播。
InputStream input = null;
try {
input = new FileInputStream("file.txt");
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
} finally {
if(input != null){
input.close();
}
}
在这种情况下,如果 try 块和 finally 块(当 InputStream 关闭时)中都发生异常,则会抛出最后一个异常,即使从 try 块抛出的异常可能与传播更相关。
try(FileInputStream input = new FileInputStream("file.txt")) {
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
}
在这种情况下,如果 try 块和 finally 块中同时发生异常,则会传播第一个