Sintaks coba-dengan-sumber daya Java 7 (juga dikenal sebagai blok ARM ( Manajemen Sumber Daya Otomatis )) bagus, pendek dan mudah ketika menggunakan hanya satu AutoCloseable
sumber daya. Namun, saya tidak yakin apa idiom yang benar ketika saya perlu mendeklarasikan banyak sumber daya yang saling bergantung, misalnya a FileWriter
dan a BufferedWriter
yang membungkusnya. Tentu saja, pertanyaan ini menyangkut masalah ketika beberapa AutoCloseable
sumber daya dibungkus, tidak hanya dua kelas khusus ini.
Saya datang dengan tiga alternatif berikut:
1)
Ungkapan naif yang saya lihat adalah mendeklarasikan hanya pembungkus tingkat atas dalam variabel yang dikelola ARM:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Ini bagus dan pendek, tetapi rusak. Karena yang mendasarinya FileWriter
tidak dideklarasikan dalam variabel, itu tidak akan pernah ditutup langsung di finally
blok yang dihasilkan . Itu akan ditutup hanya melalui close
metode pembungkus BufferedWriter
. Masalahnya adalah, bahwa jika pengecualian dilemparkan dari bw
konstruktor, itu close
tidak akan dipanggil dan karena itu yang mendasarinya FileWriter
tidak akan ditutup .
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
}
}
Di sini, sumber daya pokok dan pembungkus dideklarasikan dalam variabel yang dikelola ARM, sehingga keduanya pasti akan ditutup, tetapi dasarnya fw.close()
akan dipanggil dua kali : tidak hanya secara langsung, tetapi juga melalui pembungkus bw.close()
.
Ini seharusnya tidak menjadi masalah untuk dua kelas khusus ini yang keduanya mengimplementasikan Closeable
(yang merupakan subtipe dari AutoCloseable
), yang kontraknya menyatakan bahwa beberapa panggilan close
diizinkan:
Menutup aliran ini dan melepaskan sumber daya sistem apa pun yang terkait dengannya. Jika aliran sudah ditutup maka menjalankan metode ini tidak akan berpengaruh.
Namun, dalam kasus umum, saya dapat memiliki sumber daya yang hanya menerapkan AutoCloseable
(dan tidak Closeable
), yang tidak menjamin yang close
dapat dipanggil beberapa kali:
Perhatikan bahwa tidak seperti metode tutup java.io.Closeable, metode tutup ini tidak diperlukan untuk menjadi idempoten. Dengan kata lain, memanggil metode tutup ini lebih dari sekali mungkin memiliki beberapa efek samping yang terlihat, tidak seperti Closeable.close yang diperlukan untuk tidak memiliki efek jika dipanggil lebih dari sekali. Namun, pelaksana antarmuka ini sangat dianjurkan untuk membuat metode mereka dekat idempoten.
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
}
}
Versi ini harus benar secara teoritis, karena hanya fw
mewakili sumber daya nyata yang perlu dibersihkan. Itu bw
sendiri tidak memiliki sumber daya apa pun, itu hanya mendelegasikan ke fw
, jadi itu harus cukup untuk hanya menutup yang mendasarinya fw
.
Di sisi lain, sintaksnya agak tidak teratur dan juga, Eclipse mengeluarkan peringatan, yang saya percaya merupakan alarm palsu, tetapi itu masih merupakan peringatan bahwa seseorang harus berurusan dengan:
Kebocoran sumber daya: 'bw' tidak pernah ditutup
Jadi, pendekatan mana yang harus ditempuh? Atau apakah saya melewatkan beberapa idiom lain yang benar ?
public BufferedWriter(Writer out, int sz)
bisa melempar IllegalArgumentException
. Juga, saya dapat memperluas BufferedWriter dengan kelas yang akan membuang sesuatu dari konstruktornya atau membuat bungkus kustom apa pun yang saya butuhkan.
BufferedWriter
konstruktor dapat dengan mudah melempar pengecualian. OutOfMemoryError
mungkin yang paling umum karena mengalokasikan sebagian besar memori untuk buffer (walaupun mungkin mengindikasikan Anda ingin me-restart seluruh proses). / Anda perlu flush
Anda BufferedWriter
jika Anda tidak dekat dan ingin menyimpan isi (umumnya hanya kasus non-pengecualian). FileWriter
mengambil apa pun yang terjadi sebagai pengkodean file "default" - lebih baik untuk menjadi eksplisit.