看到没,在第15~27行,编译器自动帮我们生成了finally块,并且在里面调用了资源的close方法,所以例子中的close方法会在运行的时候被执行。 异常屏蔽
细心的你们肯定又发现了,刚才反编译的代码(第21行)比远古时代写的代码多了一个 addsuppressed 。为了了解这段代码的用意,我们稍微修改一下刚才的例子:我们将刚才的代码改回远古时代手动关闭异常的方式,并且在 senddata 和 close 方法中抛出异常:
public class connection implements autocloseable {
public void senddata() throws exception {
throw new exception("send data");
}
@override
public void close() throws exception {
throw new myexception("close");
}
}
basic.exception.myexception: close
at basic.exception.connection.close(connection.java:10)
at basic.exception.trywithresource.test(trywithresource.java:82)
at basic.exception.trywithresource.main(trywithresource.java:7)
......
java.lang.exception: send data
at basic.exception.connection.senddata(connection.java:5)
at basic.exception.trywithresource.main(trywithresource.java:14)
......
suppressed: basic.exception.myexception: close
at basic.exception.connection.close(connection.java:10)
at basic.exception.trywithresource.main(trywithresource.java:15)
... 5 more
可以看到,异常信息中多了一个 suppressed 的提示,告诉我们这个异常其实由两个异常组成, myexception 是被suppressed的异常。可喜可贺! 注意事项
在使用try-with-resource的过程中,一定需要了解资源的 close 方法内部的实现逻辑。否则还是可能会导致资源泄露。
举个例子,在java bio中采用了大量的装饰器模式。当调用装饰器的 close 方法时,本质上是调用了装饰器内部包裹的流的 close 方法。比如:
public class trywithresource {
public static void main(string[] args) {
try (fileinputstream fin = new fileinputstream(new file("input.txt"));
gzipoutputstream out = new gzipoutputstream(new fileoutputstream(new file("out.txt")))) {
byte[] buffer = new byte[4096];
int read;
while ((read = fin.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
catch (ioexception e) {
e.printstacktrace();
}
}
}