Java 7のtry-with-resources構文(ARMブロック(自動リソース管理)とも呼ばれます)は、AutoCloseable
リソースを1つだけ使用する場合に便利で短く、簡単です。ただし、相互に依存する複数のリソースを宣言する必要がある場合、たとえばa FileWriter
とa BufferedWriter
をラップすることで、正しいイディオムが何であるかわかりません。もちろん、この質問は、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()
ます。
これは、両方が実装するこれらの2つの特定のクラスCloseable
(のサブタイプAutoCloseable
)の問題にはなりませんclose
。
このストリームを閉じ、それに関連付けられているすべてのシステムリソースを解放します。ストリームがすでに閉じている場合、このメソッドを呼び出しても効果はありません。
しかし、一般的なケースでは、私が唯一の実装リソース持つことができますAutoCloseable
(とされていないCloseable
ことを保証するものではない)、close
複数回呼び出すことができます。
java.io.Closeableのcloseメソッドとは異なり、このcloseメソッドはべき等である必要はないことに注意してください。つまり、このcloseメソッドを2回以上呼び出すと、目に見える副作用が発生する可能性があります。これは、2回以上呼び出すと効果がないことが必要な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'は決して閉じられません
それでは、どのアプローチを採用するのでしょうか。または、正しい他のイディオムを逃したことがありますか?
public BufferedWriter(Writer out, int sz)
をスローすることができIllegalArgumentException
ます。また、BufferedWriterを拡張して、コンストラクターから何かをスローするクラスや、必要なカスタムラッパーを作成するクラスを追加することもできます。
BufferedWriter
コンストラクタが簡単に例外をスローすることができます。OutOfMemoryError
バッファにかなりの量のメモリを割り当てるため、おそらく最も一般的なものです(ただし、プロセス全体を再起動する必要があることを示す場合があります)。/あなたはする必要がありflush
、あなたのBufferedWriter
お近くにないと内容(一般的に維持したい場合のみ、非例外ケースを)。FileWriter
「デフォルト」のファイルエンコーディングを取得します。明示的にすることをお勧めします。