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