Java 7 のtry-with-resources構文 (ARM ブロック ( Automatic Resource Management ) とも呼ばれます) は、AutoCloseable
リソースを 1 つだけ使用する場合に便利で、短くて簡単です。FileWriter
ただし、相互に依存する複数のリソースを宣言する必要がある場合、たとえば aと aBufferedWriter
をラップする場合、どのイディオムが正しいかわかりません。もちろん、この質問は、AutoCloseable
これら 2 つの特定のクラスだけでなく、一部のリソースがラップされている場合にも関係します。
私は次の3つの選択肢を思いつきました:
1)
私が見た単純なイディオムは、ARM 管理の変数で最上位のラッパーのみを宣言することです。
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
これは素晴らしく短いですが、壊れています。基になるものは変数で宣言されていないため、生成されたブロックFileWriter
で直接閉じられることはありません。ラッピングfinally
の 方法 で のみ 閉じます . 問題は、のコンストラクターから例外がスローされた場合、その例外が呼び出されないため、基になるものが閉じられないことです。close
BufferedWriter
bw
close
FileWriter
2)
static void printToFile2(String text, File file) {
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
ここでは、基になるリソースとラッピング リソースの両方が ARM 管理の変数で宣言されているため、どちらも確実に閉じられますが、基fw.close()
になるリソースは 2 回呼び出されます。つまり、直接だけでなく、ラッピングを通じても呼び出されbw.close()
ます。
Closeable
のサブタイプであるAutoCloseable
両方を実装するこれら 2 つの特定のクラスでは、これは問題にはなりませんclose
。
このストリームを閉じて、それに関連付けられているシステム リソースを解放します。ストリームが既に閉じられている場合、このメソッドを呼び出しても効果はありません。
ただし、一般的なケースでは、 のみを実装するAutoCloseable
(および実装しない) リソースを持つことができます。これは、複数回呼び出すことができることをCloseable
保証しません。close
java.io.Closeable の close メソッドとは異なり、この close メソッドはべき等である必要がないことに注意してください。つまり、この close メソッドを複数回呼び出すと、目に見える副作用が生じる可能性があります。これは、複数回呼び出されても効果がないことが必要な Closeable.close とは異なります。ただし、このインターフェイスの実装者は、close メソッドを冪等にすることを強くお勧めします。
3)
static void printToFile3(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
fw
クリーンアップが必要な実際のリソースを表すのはのみであるため、このバージョンは理論的に正しいはずです。自体はbw
リソースを保持せず、 に委譲するfw
だけなので、基になる を閉じるだけで十分fw
です。
一方、構文は少し不規則であり、Eclipse は警告を発行します。これは誤報だと思いますが、それでも対処しなければならない警告です。
リソース リーク: 'bw' は決して閉じられません
では、どのアプローチを採用すればよいでしょうか。それとも、正しいものである他のイディオムを見逃したことがありますか?