Closing inputstreams in Java
我在try / catch块中有以下代码
1 2 3 | InputStream inputstream = conn.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); |
我的问题是,当我必须在finally块中关闭这些流时,是否必须关闭所有3个流,或者仅关闭befferedreader会关闭所有其他流?
按照约定,包装器流(用于包装现有流)在关闭时会关闭基础流,因此在您的示例中只需关闭
通常,只关闭最外部的流是可以的,因为按照惯例,它必须触发基础流的关闭。
因此,通常代码如下所示:
1 2 3 4 5 6 7 8 9 10 | BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(conn.getInputStream())); ... in.close(); // when you care about Exception-Handling in case when closing fails } finally { IOUtils.closeQuietly(in); // ensure closing; Apache Commons IO } |
但是,在少数情况下,基础流构造函数会在流已打开的情况下引发异常。在那种情况下,上面的代码将不会关闭基础流,因为从未调用外部构造函数并且
从Java 7开始,您可以执行以下操作:
1 2 3 4 5 | try (OutputStream out1 = new ...; OutputStream out2 = new ...) { ... out1.close(); //if you want Exceptions-Handling; otherwise skip this out2.close(); //if you want Exceptions-Handling; otherwise skip this } // out1 and out2 are auto-closed when leaving this block |
在大多数情况下,在关闭时引发异常时,您不需要异常处理,因此请跳过这些显式的close()调用。
编辑
这是一些针对非信徒的代码,在这些代码中使用此模式非常重要。您可能还想阅读有关closeQuietly()方法的Apache Commons IOUtils javadoc。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | OutputStream out1 = null; OutputStream out2 = null; try { out1 = new ...; out2 = new ...; ... out1.close(); // can be skipped if we do not care about exception-handling while closing out2.close(); // can be skipped if we ... } finally { /* * I've some custom methods in my projects overloading these * closeQuietly() methods with a 2nd param taking a logger instance, * because usually I do not want to react on Exceptions during close * but want to see it in the logs when it happened. */ IOUtils.closeQuietly(out1); IOUtils.closeQuietly(out2); } |
当创建
关闭最外面的一个就足够了(即
1 2 3 4 5 6 7 8 9 10 | 513 public void close() throws IOException { 514 synchronized (lock) { 515 if (in == null) 516 return; 517 in.close(); 518 in = null; 519 cb = null; 520 } 521 } 522 } |
您只需要关闭实际资源。即使构造装饰器失败,也应关闭资源。对于输出,应该在满意的情况下刷新大多数装饰对象。
一些并发症:
- 有时,装饰器是不同的资源(某些压缩实现使用C堆)。
- 在糟糕的情况下关闭装饰器实际上会导致刷新,并产生混乱,例如实际上并未关闭基础资源。
-
看起来您的基础资源是
URLConnection ,它没有这样的disconnect /close 方法。
您可能希望考虑使用Execute Around惯用语,因此您不必重复这种事情。
我将按照打开它们的相反顺序关闭所有它们,好像打开它们时会将阅读器推到堆栈中,而关闭将阅读器从堆栈中弹出。
最后,在全部关闭之后,"阅读器堆栈"必须为空。
根据经验,应按打开它们的相反顺序关闭所有组件。