26

try/catchブロックに次のコードがあります

 InputStream inputstream = conn.getInputStream();
 InputStreamReader inputstreamreader = new  InputStreamReader(inputstream);
 BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

私の質問は、finallyブロックでこれらのストリームを閉じる必要がある場合、3つのストリームすべてを閉じる必要がありますか、それともbefferedreaderを閉じるだけで他のすべてのストリームが閉じますか?

4

6 に答える 6

29

慣例により、ラッパーストリーム(既存のストリームをラップする)は、閉じられたときに基になるストリームを閉じるためbufferedreader、例では閉じるだけで済みます。また、通常、すでに閉じられているストリームを閉じることは無害であるため、3つのストリームすべてを閉じても問題はありません。

于 2012-06-29T14:47:10.457 に答える
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
}

それにもかかわらず、ストリームが既に開かれている場合に、基になるストリーム コンストラクターが例外を発生させるというまれなケースがあるかもしれません。その場合、外側のコンストラクターが呼び出されず、innull であるため、上記のコードは基になるストリームを閉じません。したがって、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

ほとんどの場合、クローズ中に発生した場合の例外処理は必要ないため、これらの明示的な 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);
    }

@Tom の「アドバイス」を使用すると、の作成で例外が発生out1したときに開いたままになります。out2このアドバイスは、It's a continual source of errors for obvious reasons.まあ、私は盲目かもしれませんが、私には明らかではありません. トムのパターンはエラーが発生しやすいのに対し、私のパターンは考えられるすべてのユースケースで馬鹿げた安全です。

于 2012-06-29T14:55:25.057 に答える
3

最も外側のものを閉じるだけで十分です (つまり、BufferedReader)。BufferedReader のソース コードを読むとReader、独自の close メソッドが呼び出されたときに内部を閉じることがわかります。

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   }
于 2012-06-29T14:49:59.577 に答える
0

実際のリソースを閉じる必要があるだけです。デコレータの構築に失敗した場合でも、リソースを閉じる必要があります。出力については、幸せな場合に最も多くのデコレータ オブジェクトをフラッシュする必要があります。

いくつかの合併症:

  • デコレーターが異なるリソースである場合があります (一部の圧縮実装では C ヒープが使用されます)。
  • 悲しいケースでデコレータを閉じると、実際にはフラッシュが発生し、基礎となるリソースを実際に閉じないなどの混乱が生じます。
  • 基礎となるリソースは/メソッド自体URLConnectionを持たない のようです。disconnectclose

この種のものを複製する必要がないように、Execute Around イディオムの使用を検討することをお勧めします。

于 2012-06-29T14:54:58.690 に答える
0

それらを開くとリーダーがスタックにプッシュされ、閉じるとスタックからリーダーがポップされるかのように、開いたときと逆の順序でそれらすべてを閉じます。

最後に、すべてを閉じた後、「リーダースタック」は空でなければなりません。

于 2012-06-29T14:48:30.497 に答える
0

経験則として、開いたときと逆の順序ですべてを閉じる必要があります。

于 2012-06-29T14:47:35.900 に答える