39

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();
}

これはしたほうがよいでしょうか?

4

4 に答える 4

84

javadocは非常に明示的です。

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

コードをざっと見てみると、次のように確認できます。

public void close() throws IOException {
}
于 2013-01-26T23:13:51.743 に答える
6

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

于 2013-01-26T23:15:15.623 に答える
4

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

さらに、後で説明するように、コードにボイラープレートが追加され、メイン ロジックがわかりにくくなるため、通常はa を閉じるべきではありません。StringWriterただし、注意して意図的にこれを行っていることを読者に安心させるために、次の事実にコメントすることをお勧めします。

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

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

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);
    }
}

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

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

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

于 2015-09-01T03:35:48.767 に答える
0

メソッドの最後には への参照が残っていないwriterため、GC によって解放されます。

于 2013-01-26T23:15:48.910 に答える