try-with-resource
try-with-resource
InputStream实现了Closable接口,就不用显式地写finally然后in.close()啦~
try(InputStream in = new InputStream(...);){
...
}
【原理】反编译后发现其实是自动生成的finally块然后调用close()方法~
【异常屏蔽】如果在finally中也发生了异常,我们看到的是最后一个抛出的异常,而前面的异常被忽略了。
解决办法:JAVA7中为Throwable类增加了addSuppressed方法,把被抑制的异常记录下来。
public class ReadFile {
public void read(String filename) throws Throwable {
FileInputStream input = null;
Throwable exception = null; // 用全局的一个变量承载它
try {
input = new FileInputStream(filename);
} catch (IOException ex) {
exception = ex;
} finally {
if(input != null){
try {
// 如果在finally中也出现了异常
input.close();
} catch (IOException ex2) {
if(exception != null){
// 这里把第二个异常信息加到exception中
exception.addSuppressed(ex2);
}else{
exception = ex2;
}
}
}
// 最后把异常抛出来,不然就被吞了!!
if(exception != null){
throw exception;
}
}
}
}
注意事项
在使用try-with-resource的过程中,一定需要了解资源的 close 方法内部的实现逻辑。否则还是可能会导致资源泄露。
// wrong
try (FileInputStream fin = new FileInputStream(new File("input.txt"));
GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(new File("out.txt")))) {
....
} catch (IOException e) {
e.printStackTrace();
}
GZIPOutputStream 实际上是 FileOutputStream 的装饰器,它的close方法本质还是调用FileOutputStream::close()方法,
如果在out.close()前发生了异常,就导致outPutStream没有关闭!
// right
try (FileInputStream fin = new FileInputStream(new File("input.txt"));
FileOutputStream fout = new FileOutputStream(new File("out.txt"));
GZIPOutputStream out = new GZIPOutputStream(fout)) {
....
} catch (IOException e) {
e.printStackTrace();
}