web-dev-qa-db-ja.com

ストリングライターを閉じないとリークが発生しますか?

Java= GCは最終的にオブジェクトをクリーンアップすることを理解していますが、文字列ライターを閉じないことは悪い習慣かどうかを尋ねています。現在私はこれを行っています:

 private static String processTemplate(final Template template, final Map root) {
        StringWriter writer = new StringWriter();
        try {
            template.process(root, writer);
        } catch (TemplateException e) {
            logger.error(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        finally {

        }

        return writer.toString();
    }

ライターを閉じて、次のような新しい文字列を作成する必要があります。

String result = "";

...

finally {
  result = writer.toString();
  writer.close();
}

これを行う方が良いですか?

33
Blankman

javadoc は非常に明示的です。

StringWriterを閉じても効果はありません。

そして、 コード をざっと見ると、それが確認できます。

public void close() throws IOException {
}
70
assylias

非メモリリソースを保持していません。他と同じようにガベージコレクションされます。 close()は、他のライターオブジェクトがクリーンアップする必要のあるリソースを保持しているために存在する可能性があり、インターフェイスを満足させるためにclose()が必要です。

4
James Curran

いいえ、StringWriterを閉じなくてもリークは発生しません。前述のように、StringWriter#close()はnopであり、ライターは外部リソースではなくメモリのみを保持するため、これらはライターが収集するときに収集されます。収集されます。 (明示的に、オブジェクトへの参照を、オブジェクトをエスケープしないプライベートフィールドに保持します。具体的には、StringBufferなので、外部参照はありません。)

さらに、一般的にStringWriterを閉じるべきではありませんコードに定型文を追加し、メインロジックを覆い隠します。わかります。ただし、読者が注意深くこれを意図的に行っていることを読者に安心させるために、この事実についてコメントすることをお勧めします。

_// Don't need to close StringWriter, since no external resource.
Writer writer = new StringWriter();
// Do something with writer.
_

ライターを閉じたい場合、最もエレガントなのは try-with-resources を使用することです。これにより、tryブロックの本体を終了するときにclose()が自動的に呼び出されます。

_try (Writer writer = new StringWriter()) {
    // Do something with writer.
    return writer.toString();
}
_

ただし、 Writer#close()IOExceptionをスローするため、メソッドはIOExceptionもスローする必要があります。 、またはそれをキャッチして、コンパイラに処理されたことを証明する必要があります。これは非常に複雑です。

_Writer writer = new StringWriter();
try {
    // Do something with writer, which may or may not throw IOException.
    return writer.toString();
} finally {
    try {
        writer.close();
    } catch (IOException e) {
        throw new AssertionError("StringWriter#close() should not throw IOException", e);
    }
}
_

コードの本体からスローされたIOExceptionを誤って飲み込む可能性があるため、このレベルのボイラープレートが必要なのは、tryブロック全体にキャッチを配置できないためです。現在何もない場合でも、将来追加される可能性があるため、コンパイラーから警告を受ける必要があります。 AssertionErrorStringWriter#close()の現在の動作を文書化しており、将来のリリースで変更される可能性がありますが、それは非常にまれです。また、試行の本体で発生する可能性のある例外をマスクします(繰り返しますが、これは実際には発生しないはずです)。これは定型的で複雑すぎるため、close()を省略して理由をコメントする方が明らかに良いでしょう。

微妙な点は、Writer#close()IOExceptionをスローするだけでなく、 StringWriter#close() もスローするため、例外を排除できないことです変数をStringWriterではなくWriterにします。これは、StringReaderdifferentであり、close()メソッドを使用して、例外をスローするしないことを指定します! 私の答え から StringReaderを閉じる必要がありますか? を参照してください。これは間違っているように見えるかもしれません–なぜ、例外をスローするだけのメソッドがあるのでしょうか? –ただし、これは一般的にライターにとっての問題であるため、将来的にIOExceptionを閉じる可能性を残しておくために、おそらく上位互換性のためです。 (それは単に間違いかもしれません。)

要約すると、StringWriterを閉じないのは問題ありませんが、通常の正しいこと、つまりtry-with-resourcesを実行しない理由は、close()が例外をスローすると宣言しているからです。実際にはスローされないこと、そしてこれを正確に処理することは多くの定型文です。それ以外の場合は、従来の正しいリソース管理パターンを使用して、問題や頭の引っかき傷を防止することをお勧めします。

3
Nils von Barth