今天要讨论的话题是jdk7中引进的try-with-resource。当看到这个名字的第一时间,不清楚的朋友肯定会猜到这个新玩意跟try有点关系,但为什么还要with resource,即带上所谓的“资源”呢?


先谈谈什么是资源

什么是资源呢?我们可以举一个最简单的例子,钱就是资源!人人都想要的东西就是资源,反之,人人都讨厌的东西就是垃圾。

所以此时,资源有一个明显的特征,即抢手!

在软件开发中,资源同样也是那些“抢手货”,最明显的例子就是内存了。电脑中所有的程序都依赖于内存才能运行,谁抢到的内存多,谁运行的就快(相对而言),给用户的体验就更好。所以为了解决软件们对内存的竞争,编程语言越来越注重对内存的管理,而多数程序员也都知道,从C++到Java就明显基于这一考虑。

释放资源的控制权

C++到Java的演变,有一个大的变化就是内存的释放权从程序员自身变成了JVM,如此可以极大降低内存泄露的风险,而jdk7中引进的try-with-resource,正是基于同样的考虑,将资源的释放权从程序员的手中拿回来,然后强制进行释放。

所以,try-with-resource带来的最大的变化,就是资源释放的强制性,同时也给编程提供了一定的便利性。

那么try-with-resource中,资源的释放行为是如何定义的呢?这里就不得不提一下AutoCloseable接口了!通过其名字我们就能猜测出,这个接口专注于“关闭”这一行为,而且关闭还具备自动化的特性,果不其然,这个接口里只定义了一个方法,方法的名字正是close()。

到这里应该猜到了吧,从JDK7开始,对资源的定义可以简单的描述为:

凡是实现了AutoCloseable接口的类的实例都可以被看作是一种资源,程序员们只要自定义close()的实现,完成对资源的释放(其实你爱干嘛干嘛,不但不释放资源,你再申请其它的资源都没事)就OK了,至于close()方法的具体调用,try-with-resource为你负责!

TRY-WITH-RESOURCE长什么样

说了这么多废话,不如下图来的实在,直接给出了try-with-resource的用法:

各位看到上图之后会发现,try-with-resource跟传统的try-catch-finally的用法基本一致,只不过try后面直接跟了一对括号(),然后括号里面的表达式即为try-with-resource表达式。

重点一来了:try-with-resource是一种表达式,而不是类似于try-catch-finally的控制类语法!

既然是一种表达式,那就很好理解了,括号里你可以写多个子表达式,它们之间使用经典的也是默认的也是其它表达式采用的分隔符--分号进行分隔就可以了。

我们再看一下上图中的ResourceA和ResourceB是个什么玩意:

ResourceA和ResourceB都继承自BaseResource,而BaseResource实现了AutoCloseable接口,按照JDK7以后的说法,ResourceA和ResourceB都是一种资源了,所以:

重点二来了:try-with-resource表达式里声明的对象必须是一种资源,即必须要直接或间接的实现了AutoCloseable接口!

如果try-with-resource表达式里声明的对象不是一种资源,编译都不让你通过!

TWR和TCF,“你们不一样?”

先看一个对比的例子,即同样功能的代码,先采用try-with-resource的方式写一遍,再使用经典的try-catch-finally写一遍,其中的差异,一目了然!

第一,也是最重要的一点,TWR中,需要释放的资源不用在finally块中进行手工释放了,因为TWR“好自为之”了。一方面让代码更加简洁,另一方面,也避免了“手残”而导致的资源忘关闭。

第二,TWR表达式中声明的变量,其生命周期在try代码块中依然有效,而TCF模式下,多数需要在try之前进行声明,以便在catch和finally代码块中可以继续访问该变量。

以上两点呢,就是眼见为实的好处。

到目前为止,可能会有朋友会问,try-with-resource表达式可以继续使用catch和finally进行相关的操作吗?答案是当然可以!再重申一遍,try-with-resource只是一种表达式,不是控制性的语法!以前的try-catch-finally怎么用,现在还是怎么用,只是有一点需要明确:

catch和finally的代码块是在资源的close方法执行之后才会执行!

TWR的“小坑坑”

这里的小坑坑其实就是“异常压制”。所谓异常压制就是当一块代码有多个地方同时抛出异常时,某个地方抛出的异常不会被catch到。针对try-with-resource而言,会被压制的异常就是资源即AutoCloseable的close方法抛出的异常,资源在创建以及try代码块中抛出的异常不会被压制。

这种压制机制其实很好理解,因为close方法不是程序员手工调用的,所以程序员就不会注意close方法抛出的异常,顺其自然,也就没有“责任”去捕获这些异常了。

结束语

try-with-resource这功能挺好的,建议所有需要操作资源的代码都使用TWR表达式,如此一来可以“跟上潮流”。