Try-with-resources是java7中一个新的异常处理机制,能够很容易地关闭在try-catch语句块中使用的资源。
一、利用Try-Catch-Finally管理资源(旧的代码风格)
在java7以前,程序中使用的资源需要被明确地关闭
读取文件:
查看源代码打印帮助01 | PRivate static void printFile() throws IOException { |
02 | InputStream input = null ; |
05 | input = new FileInputStream( "file.txt" ); |
07 | int data = input.read(); |
09 | System.out.print(( char ) data); |
正如你所看到的,try语句块中有3个地方会抛出异常,finally语句块中有一个地方会出异常。假设try语句块抛出一个异常,然后finally语句块被执行。同样假设finally语句块也抛出了一个异常。那么,即使try语句块中抛出的异常与异常传播更相关,最终还是finally语句块中抛出的异常会根据调用栈向外传播。
在java7中,对于上面的例子可以用try-with-resource 结构这样写:
01 | private static void printFileJava7() throws IOException { |
03 | try (FileInputStream input = new FileInputStream( "file.txt" )) { |
05 | int data = input.read(); |
07 | System.out.print(( char ) data); |
注意方法中的第一行:
1 | try (FileInputStream input = new FileInputStream( "file.txt" )) { |
这就是try-with-resource 结构的用法。FileInputStream 类型变量就在try关键字后面的括号中声明。而且一个FileInputStream 类型被实例化并被赋给了这个变量。
当try语句块运行结束时,FileInputStream 会被自动关闭。这是因为FileInputStream 实现了java中的java.lang.AutoCloseable接口。所有实现了这个接口的类都可以在try-with-resources结构中使用。
当try-with-resources结构中抛出一个异常,同时FileInputStreami被关闭时(调用了其close方法)也抛出一个异常,try-with-resources结构中抛出的异常会向外传播,而FileInputStreami被关闭时抛出的异常被抑制了。这与文章开始处利用旧风格代码的例子(在finally语句块中关闭资源)相反。
二、使用多个资源
你可以在块中使用多个资源而且这些资源都能被自动地关闭。下面是例子:
01 | private static void printFileJava7() throws IOException { |
03 | try ( FileInputStream input = new FileInputStream( "file.txt" ); |
04 | BufferedInputStream bufferedInput = new BufferedInputStream(input) |
07 | int data = bufferedInput.read(); |
09 | System.out.print(( char ) data); |
10 | data = bufferedInput.read(); |
上面的例子在try关键字后的括号里创建了两个资源——FileInputStream 和BufferedInputStream。
当程序运行离开try语句块时,这两个资源都会被自动关闭。
这些资源将按照他们被创建顺序的逆序来关闭。首先BufferedInputStream 会被关闭,然后FileInputStream会被关闭。
三、自定义AutoClosable 实现
这个try-with-resources结构里不仅能够操作java内置的类。你也可以在自己的类中实现java.lang.AutoCloseable接口,然后在try-with-resources结构里使用这个类。
AutoClosable 接口仅仅有一个方法close(),接口定义如下:
1 | public interface AutoClosable { |
3 | public void close() throws Exception; |
任何实现了这个接口的方法都可以在try-with-resources结构中使用。下面是一个简单的例子:
01 | public class MyAutoClosable implements AutoCloseable { |
04 | System.out.println( "MyAutoClosable doing it!" ); |
08 | public void close() throws Exception { |
09 | System.out.println( "MyAutoClosable closed!" ); |
doIt()是方法不是AutoClosable 接口中的一部分,之所以实现这个方法是因为我们想要这个类除了关闭方法外还能做点其他事。
下面是MyAutoClosable 在try-with-resources结构中使用的例子:
1 | private static void myAutoClosable() throws Exception { |
3 | try (MyAutoClosable myAutoClosable = new MyAutoClosable()){ |
当方法myAutoClosable.doIt()被调用时,下面是打印到System.out的输出:
1 | MyAutoClosable doing it! |
通过上面这些你可以看到,不论try-catch中使用的资源是自己创造的还是java内置的类型,try-with-resources都是一个能够确保资源能被正确地关闭的强大方法。
四、try-with-resources 在 JDK 9 中的改进如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中直接使用该变量,而无需在 try-with-resources 语句中声明一个新变量。例如:给定资源的声明
// A final resourcefinal Resource resource1 = new Resource("resource1");// An effectively final resourceResource resource2 = new Resource("resource2");老方法编写代码来管理这些资源是类似的:
// Original try-with-resources statement from JDK 7 or 8try (Resource r1 = resource1; Resource r2 = resource2) { // Use of resource1 and resource 2 through r1 and r2.}而新方法可以是
// New and improved try-with-resources statement in JDK 9try (resource1; resource2) { // Use of resource1 and resource 2.}让我们一起遨游在代码的海洋里!