若是使用传统try-catch-finally管理资源连接,代码多是下面这样,finally代码远远多于业务代码。
为了增长代码可读性和可维护性,建议使用jdk7 提供的新特性try-with-resource(只能在表面上省去finally块关闭资源的逻辑):
即:try(资源定义){
业务逻辑
}
其实这只是个语法糖,由于编译时编译器会自动帮代码加上finally并调用close方法(前提是这些资源类都实现了Closeable接口)。(将你编译好的.class文件拖入idea便可看到编译后的代码(idea能够反编译出来))
能够看出finally代码块中除了正常关闭链接代码外,还包含了addSuppressed()方法,这个方法做用是保证一个异常不被另一个异常抑制而没法抛出,好比try-catch块代码抛异常,程序会继续执行finally代码,但若是finally代码又抛错,就会致使try-catch的异常没法正常抛出,此时可使用addSuppressed()方法能够将被抑制的异常也抛出。
参考连接:https://my.oschina.net/fhd/blog/324484。
try-with-resource代码确实好用,程序可读性有所提升。但看着上面第二张图片的代码,你是否怀疑资源最大可能被关闭?是否编译器加上的fin.close()方法和out.close()方法就完整了?不是的。请看GZIPOutputStream类的close()方法
下面是GZIPOutputStream类的父类的close()方法(GZIPOutputStream类没重写)
close()方法时先调用finish()方法再调用out.close()方法,因此若是finish()方法顺利执行,那么out.close()方法确实能够顺利执行。
但进去finish()方法看看,
finish()方法是声明了会抛异常的,也就是finish()方法不见得必定正常执行,也就致使了out.close()方法在finish()方法抛异常时不能被调用,进而致使资源没有被关闭。
对于各个资源类的包装类,内部都是使用装饰者模式实现的,例子中调用out.close()方法,深层次仍是调用FileOutputStream类的close方法,既然这样,咱们程序就应该最大程度确保最内层资源的close()方法被调用(就算包装类的close()方法抛异常),才能最大程度上保证资源被关闭。
所以上面try-with-resource例子的流嵌套是不合理的,应该使用下面这种方式(分开定义每一个Closeable类的资源):
看上面分开定义后编译生成的代码(以下):
显然,每一层Closeable类的资源的close()方法都被显式地调用。保证了资源最大程度的关闭。ide