在Java中关闭输入流

com*_*ose 24 java inputstream

我在try/catch块中有以下代码段

 InputStream inputstream = conn.getInputStream();
 InputStreamReader inputstreamreader = new  InputStreamReader(inputstream);
 BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
Run Code Online (Sandbox Code Playgroud)

我的问题是,当我必须关闭finally块中的这些流时,是否必须关闭所有3个流,或者只是关闭befferedreader将关闭所有其他流?

cas*_*nca 28

按照惯例,封装流(包装现有流)在关闭时关闭底层流,因此只需bufferedreader在示例中关闭.此外,关闭已经关闭的流通常是无害的,因此关闭所有3个流不会受到伤害.

  • @Soronthar然后,该流实现不受合同的约束,合同规定:“如果流已关闭,则调用此方法无效。”所有有效的实现必须具有以下行为。关闭已经关闭的流是完全合法的(也是常见的)。通常,您第一次在try块中关闭它,第二次在finally块中关闭,其中try块中的关闭使您有机会对异常做出反应,而finally块中的关闭是为了确保关闭。 (2认同)
  • 这不仅仅是约定俗成的,它是指定的。参见例如 FilerInputStream.close()。 (2认同)

Fab*_*ney 5

通常可以关闭最外层的流,因为按照惯例,它必须在底层流上触发关闭.

所以通常代码看起来像这样:

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
}
Run Code Online (Sandbox Code Playgroud)

然而,在极少数情况下,基础流构造函数会引发流已经打开的异常.在这种情况下,上面的代码不会关闭底层流,因为外部构造函数从未被调用并且in为null.所以finally块不会关闭任何东西,而是打开底层流.

从Java 7开始,您可以这样做:

    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
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,您不希望在关闭时引发异常处理,因此请跳过这些显式的close()调用.

编辑 这里是非信徒的一些代码,使用这种模式是非常重要的.您可能还想阅读关于closeQuietly()方法的Apache Commons IOUtils javadoc .

    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);
    }
Run Code Online (Sandbox Code Playgroud)

使用@ Tom的"建议"将out1在创建out2异常时保持打开状态.这个建议是来自某人谈论It's a continual source of errors for obvious reasons.嘛,我可能是盲目的,但这对我来说并不明显.我的模式在我可以想到的每个用例中都是白痴安全的,而Tom的模式容易出错.