Java try-with-resources 结构是在 Java 7 中添加的。在 Java 7 之前,管理需要显式关闭的资源有些繁琐。您必须手动处理资源的正确关闭。要正确处理这项任务并不容易。要了解原因,请参阅下面的方法,该方法读取文件并将其打印到 System.out.RTF 中:
package com.hxstrive.jdk7.try_with_resources; import java.io.FileInputStream; import java.io.InputStream; /** * JDK7 新特性 try-with-resources * @author hxstrive.com */ public class TryWithResourcesDemo13 { public static void main(String[] args) throws Exception { InputStream input = null; try { input = new FileInputStream("D:\\test.txt"); // 可能会出错,文件不存在 int data = input.read(); // 读取可能会出错 while(data != -1){ System.out.print((char) data); data = input.read(); // 读取可能会出错 } } finally { if(input != null){ input.close(); // 关闭资源,也可能会出错 } } } }
正如上面,异常可能发生在 try 代码块中的 3 个地方,以及 finally 代码块中的 1 个地方。
无论 try 代码块是否抛出异常,finally 代码块都会被执行。这意味着,无论 try 代码块中发生了什么,InputStream 都会被关闭。或者说,试图关闭。如果关闭失败,InputStream 的 close() 方法也会抛出异常。
试想一下,异常是从 try 代码块内部抛出的。然后执行 finally 代码块。再假设 finally 代码块也抛出了异常。你认为哪个异常会在调用栈中向上传播?例如:
package com.hxstrive.jdk7.try_with_resources; import java.io.FileInputStream; import java.io.InputStream; /** * JDK7 新特性 try-with-resources * @author hxstrive.com */ public class TryWithResourcesDemo14 { public static void main(String[] args) throws Exception { InputStream input = null; try { input = new FileInputStream("D:\\test.txt"); // 可能会出错 int data = input.read(); // 可能会出错 while(data != -1){ System.out.print((char) data); data = input.read(); // 可能会出错 } System.out.println(); throw new Exception("try exception"); } finally { if(input != null){ input.close(); // 关闭资源,也可能会出错 } throw new Exception("finally exception"); } //结果: //You have to believe in yourself. That's the secret of success. Charles Chaplin //Genius is one percent inspiration and ninety-nine percent perspiration. Thomas Edison //Exception in thread "main" java.lang.Exception: finally exception // at com.hxstrive.jdk7.try_with_resources.TryWithResourcesDemo14.main(TryWithResourcesDemo14.java:28) } }
从上例可知,从 finally 代码块中抛出的异常会被上传到调用堆栈,即使从 try 代码块中抛出的异常可能更适合上传到调用堆栈。