假设所有流都已创建好,是的,只需关闭bw
很好与这些流实现;但这是一个很大的假设。
I'd use 尝试资源 (tutorial)这样构造引发异常的后续流的任何问题都不会导致先前的流挂起,因此您不必依赖具有调用来关闭基础流的流实现:
try (
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
BufferedWriter bw = new BufferedWriter(osw)
) {
// ...
}
请注意您不再打电话close
at all.
重要的提示:要让 try-with-resources 关闭它们,您must在打开流时将流分配给变量,不能使用嵌套。如果您使用嵌套,则在构造后续流之一期间会出现异常(例如,GZIPOutputStream
) 将使由其中的嵌套调用构造的任何流保持打开状态。从JLS §14.20.3:
try-with-resources 语句的参数化为变量(称为资源)在执行之前初始化try
执行后,按照与初始化相反的顺序自动阻止并关闭try
block.
注意“变量”这个词(我的重点).
例如,不要这样做:
// DON'T DO THIS
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new GZIPOutputStream(
new FileOutputStream(createdFile))))) {
// ...
}
...因为有一个例外GZIPOutputStream(OutputStream)构造函数(它说它可能会抛出IOException
,并将标头写入底层流)将留下FileOutputStream
打开。由于某些资源具有可能会抛出异常的构造函数,而其他资源则不会,因此单独列出它们是一个好习惯。
我们可以用这个程序仔细检查我们对 JLS 部分的解释:
public class Example {
private static class InnerMost implements AutoCloseable {
public InnerMost() throws Exception {
System.out.println("Constructing " + this.getClass().getName());
}
@Override
public void close() throws Exception {
System.out.println(this.getClass().getName() + " closed");
}
}
private static class Middle implements AutoCloseable {
private AutoCloseable c;
public Middle(AutoCloseable c) {
System.out.println("Constructing " + this.getClass().getName());
this.c = c;
}
@Override
public void close() throws Exception {
System.out.println(this.getClass().getName() + " closed");
c.close();
}
}
private static class OuterMost implements AutoCloseable {
private AutoCloseable c;
public OuterMost(AutoCloseable c) throws Exception {
System.out.println("Constructing " + this.getClass().getName());
throw new Exception(this.getClass().getName() + " failed");
}
@Override
public void close() throws Exception {
System.out.println(this.getClass().getName() + " closed");
c.close();
}
}
public static final void main(String[] args) {
// DON'T DO THIS
try (OuterMost om = new OuterMost(
new Middle(
new InnerMost()
)
)
) {
System.out.println("In try block");
}
catch (Exception e) {
System.out.println("In catch block");
}
finally {
System.out.println("In finally block");
}
System.out.println("At end of main");
}
}
...其输出为:
Constructing Example$InnerMost
Constructing Example$Middle
Constructing Example$OuterMost
In catch block
In finally block
At end of main
请注意,没有调用close
there.
如果我们修复main
:
public static final void main(String[] args) {
try (
InnerMost im = new InnerMost();
Middle m = new Middle(im);
OuterMost om = new OuterMost(m)
) {
System.out.println("In try block");
}
catch (Exception e) {
System.out.println("In catch block");
}
finally {
System.out.println("In finally block");
}
System.out.println("At end of main");
}
然后我们得到适当的close
calls:
Constructing Example$InnerMost
Constructing Example$Middle
Constructing Example$OuterMost
Example$Middle closed
Example$InnerMost closed
Example$InnerMost closed
In catch block
In finally block
At end of main
(是的,两次致电InnerMost#close
是正确的;一个来自Middle
,另一个来自 try-with-resources。)