某些资源在尝试关闭时也会抛出异常。如果某个资源在尝试关闭时抛出异常,在同一 try-with-resources 块中打开的其他资源仍会被关闭。关闭所有资源后,尝试关闭资源失败时产生的异常将在调用堆栈中向上传播。例如:
package com.hxstrive.jdk7.try_with_resources;
/**
* JDK7 新特性 try-with-resources
* @author hxstrive.com
*/
public class TryWithResourcesDemo5 {
static class MyResource1 implements AutoCloseable {
@Override
public void close() throws Exception {
// 关闭抛出异常
throw new Exception("MyResource1.close");
}
}
static class MyResource2 implements AutoCloseable {
@Override
public void close() throws Exception {
// 即使 MyResource1 关闭抛出了异常,也会执行
System.out.println("MyResource2.close");
}
}
public static void main(String[] args) throws Exception {
try(
MyResource1 resource1 = new MyResource1();
MyResource2 resource2 = new MyResource2()
) {
//...
}
//结果:
//MyResource2.close
//Exception in thread "main" java.lang.Exception: MyResource1.close
}
}如果多个资源关闭尝试抛出了多个异常,则第一个遇到的异常将向上传播到调用堆栈。其余异常将被抑制。例如:
package com.hxstrive.jdk7.try_with_resources;
import java.util.Arrays;
/**
* JDK7 新特性 try-with-resources
* @author hxstrive.com
*/
public class TryWithResourcesDemo6 {
static class MyResource1 implements AutoCloseable {
@Override
public void close() throws Exception {
// 关闭抛出异常
System.out.println("MyResource1.close()");
throw new Exception("MyResource1.close");
}
}
static class MyResource2 implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("MyResource2.close()");
throw new Exception("MyResource2.close");
}
}
public static void main(String[] args) throws Exception {
try {
try (
MyResource1 resource1 = new MyResource1();
MyResource2 resource2 = new MyResource2()
) {
//...
}
} catch (Exception e) {
// 输出抑制的异常列表
System.out.println(Arrays.toString(e.getSuppressed()));
e.printStackTrace();
}
//结果:
//MyResource2.close()
//MyResource1.close()
//[java.lang.Exception: MyResource1.close]
//java.lang.Exception: MyResource2.close
}
}如果在 try-with-resources 代码块内和关闭资源(调用 close() 时)时都出现异常,则 try 代码块内出现的异常将在调用堆栈中向上传播。试图关闭资源时抛出的异常将被抑制。这与普通 try-catch-finally 代码块中的情况相反,在普通 try-catch-finally 代码块中,最后遇到的异常才会在调用栈中向上传递。例如:
package com.hxstrive.jdk7.try_with_resources;
import java.util.Arrays;
/**
* JDK7 新特性 try-with-resources
* @author hxstrive.com
*/
public class TryWithResourcesDemo4 {
static class MyResource implements AutoCloseable {
private String name;
private boolean closeFlag;
public MyResource(String name, boolean closeFlag) {
this.name = name;
this.closeFlag = closeFlag;
}
@Override
public void close() throws Exception {
System.out.println("close");
if(closeFlag) {
throw new RuntimeException(this.name + " close error");
}
}
public void doSomething(boolean doFlag) {
System.out.println("doSomething");
if(doFlag) {
throw new RuntimeException(this.name + " doSomething error");
}
}
}
public static void main(String[] args) throws Exception {
// 如果 try-with-resources 代码块和关闭资源均出现异常,则抛出代码块中的异常,抑制关闭资源时出现的异常。
try {
try (MyResource resource = new MyResource("test", true)) {
resource.doSomething(true);
}
} catch (Exception e) {
// getSuppressed() 方法返回一个数组,其中包含为传递此异常而抑制的所有异常,
// 通常是通过 try-with-resources 语句抑制的异常。如果没有异常被抑制或抑制被禁用,则返回空数组。
// 该方法是线程安全的。对返回数组的写入不会影响以后对该方法的调用。
System.out.println(Arrays.toString(e.getSuppressed()));
e.printStackTrace();
}
//结果:
//doSomething
//close
//[java.lang.RuntimeException: test close error] 这就是被抑制的异常列表
//java.lang.RuntimeException: test doSomething error
//...
}
}请记住,在 try 代码块中只能抛出一个异常。一旦抛出异常,就会退出 try 代码块,并尝试关闭资源。