前言
无论是使用文件IO流,还是网络Socket流,都免不了调用close()
将流关闭。如果需要操作的流过多,就会导致混乱。
一旦忘记将关闭方法放到finally
中,很有可能出现流未被关闭,占用大量内存空间的问题。
流程简化
对比
try-catch-finally
1 AC ac = null;
2 AC2 ac2 = null;
3 try {
4 ac = new AC();
5 ac2 = new AC2();
6 } catch (Exception e) {
7 } finally {
8 ac.close();
9 ac2.close();
10 }
try-with-resources
1 try (AC ac = new AC();
2 AC2 ac2 = new AC2()) {
3 } catch (Exception e) {
4 }
可以很明显的看到,try-with-resources
会自动调用类中的close()
方法,简化了流程,提高了代码的整洁度。
AutoCloseable
AutoCloseable
是Java的内置接口,继承这个接口并且按要求新建close()
方法,该类就能被try-with-resources
语法所支持。
示例
还记得我们刚才演示使用的两个类:AC
和AC2
吗?它们的代码如下:
AC.java
1public class AC implements AutoCloseable {
2 @Override
3 public void close() throws Exception {
4 System.out.println("Program has been closed pretended.");
5 }
6
7 //默认静态方法,在被实例化时执行
8 static {
9 System.out.println("Program running.");
10 }
11}
AC2.java
1public class AC2 implements AutoCloseable {
2 @Override
3 public void close() throws Exception {
4 System.out.println("Program 2 has been closed pretended.");
5 }
6
7 static {
8 System.out.println("Program 2 running.");
9 }
10}
AC2
和AC
在实现上是相同的。我创建两个类的原因是想让大家知道try-with-resources可以支持同时进行多个类的关闭
。再编写一个主方法,运行测试:
Main.java
1public class Main {
2 public static void main(String[] args) {
3 try (AC ac = new AC();
4 AC2 ac2 = new AC2()) {
5 //这里假装执行了有用的代码
6 Thread.sleep(2000);
7 } catch (Exception e) {
8 }
9 }
10}
测试
运行结果
1Program running.
2Program 2 running.
3(这里有2秒的延时)
4Program 2 has been closed pretended.
5Program has been closed pretended.
可以看到,try-with-resource
对类进行了实例化,并且在代码执行完毕后进行了回收(调用了各个类的close()
方法)。
后语
思考
仔细分析运行结果,你会发现该语法的运行规律是先进后出,后进先出。AC2
是最后被实例化的,但却是第一个被关闭了。
这种机制像什么?如果你对计算机原理有所研究的话,你会发现,堆栈就是先进后出的机制。
当然,由于try-with-resources
是Java的“语法糖”,我的知识还无法追踪到它的源码(JVM)当中去。但我们可以基本确定,try-with-resources
的实例化和回收机制,就是用类似堆栈的算法来实现的。