某些资源在尝试关闭时也会抛出异常。如果某个资源在尝试关闭时抛出异常,在同一 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 代码块,并尝试关闭资源。