Java7 开始 ,针对stream流的close()
操作有了新的写法。
之前我们都要在finally中执行close()
方法,如果用到了多个流,要写不少的多余代码,finally
中全是close()
,而且我们的写法还不一定安全(大佬可能会避免)。如下代码:
首先贴上我的两个自定义流:
class MyFileOutputStream extends FileOutputStream {
MyFileOutputStream(String name) throws FileNotFoundException {
super(name);
}
@Override
public void close() throws IOException {
System.out.println(">>>>MyFileOutputStream close");
throw new IOException("Exception in MyFileOutputStream close()");
}
public void read() {
System.out.println(">>>>MyFileOutputStream read");
}
}
class MyZipOutputStream extends ZipOutputStream {
public MyZipOutputStream(OutputStream out) {
super(out);
}
@Override
public void close() {
System.out.println(">>>>MyZipOutputStream close");
}
public void read() throws IOException {
System.out.println(">>>>MyZipOutputStream read");
throw new IOException("Exception in MyZipOutputStream read()");
}
}
关闭流的测试方法:
public static void test() throws Exception {
MyFileOutputStream file = null;
MyZipOutputStream out = null;
try {
file = new MyFileOutputStream("E:\\ppp.txt");
out = new MyZipOutputStream(file);
out.read();
} catch (Exception e) {
System.out.println("MyZipOutputStream read error");
throw new BaseException(e);
} finally {
if (null != file) {
file.close();
}
if (null != out) {
out.close();
}
}
}
main方法:
try {
test();
} catch (Exception e) {
e.printStackTrace();
}
执行结果:(注意:file.close();
是发生了异常的)
可以看到,zip流并没有被关闭,因为在finally中file.close()
发生了异常,导致后边的out.close()
没有执行。所以我们大部分的写法是有隐患的,并不完全正确。
下面采用try-with-resources
的新写法:
try (MyFileOutputStream file = new MyFileOutputStream("E:\\ppp.txt");
MyZipOutputStream o = new MyZipOutputStream(file)
) {
o.read();
} catch (Exception e) {
System.out.println("read catch");
e.printStackTrace();
}
新写法的结果:
可以看到,即使发生异常,在cache
前对这种方式对两个流都进行了关闭,而且写法简单,代码简洁又安全。看下编译后的class文件:
try {
MyFileOutputStream file = new MyFileOutputStream("E:\\ppp.txt");
Throwable var3 = null;
try {
MyZipOutputStream o = new MyZipOutputStream(file);
Throwable var5 = null;
try {
o.read();
} catch (Throwable var30) {
var5 = var30;
throw var30;
} finally {
if (o != null) {
if (var5 != null) {
try {
o.close();
} catch (Throwable var29) {
var5.addSuppressed(var29);
}
} else {
o.close();
}
}
}
} catch (Throwable var32) {
var3 = var32;
throw var32;
} finally {
if (file != null) {
if (var3 != null) {
try {
file.close();
} catch (Throwable var28) {
var3.addSuppressed(var28);
}
} else {
file.close();
}
}
}
} catch (Exception var34) {
System.out.println("read catch");
var34.printStackTrace();
}
Java替我们生成了安全的写法(应该也是大佬的写法),不用我们去费功夫了。该语法会自动对实现了AutoCloseable(Java7)
接口的类进行关闭,而原来的Closeable
继承了该接口。
**这里还有一个点,**第一个旧的打印结果中,明明read
方法也发生了异常,但是最后抛出的异常只有close
,这就是异常屏蔽。但是新的结果打印了两个异常,请注意这个词:Suppressed:
,这个就是Java7 新增的修复异常屏蔽的方法,就是Throwable.addSuppressed()
方法,看编译后的class文件,就用到了这个写法,就是把捕获的异常加到异常列表中,具体可以看源码:
private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;
public final synchronized void addSuppressed(Throwable exception) {
if (exception == this)
throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception);
if (exception == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
if (suppressedExceptions == null) // Suppressed exceptions not recorded
return;
if (suppressedExceptions == SUPPRESSED_SENTINEL)
suppressedExceptions = new ArrayList<>(1);
suppressedExceptions.add(exception);
}