Ви можете закрити зовнішній самий потік, адже вам не потрібно зберігати всі потоки, обгорнуті, і ви можете використовувати пробні ресурси Java 7.
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream(new FileOutputStream(createdFile)))) {
// write to the buffered writer
}
Якщо ви підписуєтесь на YAGNI, або вам не потрібно, вам слід лише додати код, який вам справді потрібен. Ви не повинні додавати код, який, на вашу думку, вам може знадобитися, але насправді не робить нічого корисного.
Візьміть цей приклад і уявіть, що могло піти не так, якби ви цього не зробили і який би вплив був?
try (
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
BufferedWriter bw = new BufferedWriter(osw)
) {
// ...
}
Почнемо з FileOutputStream, який закликає open
виконати всі реальні роботи.
/**
* Opens a file, with the specified name, for overwriting or appending.
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
*/
private native void open(String name, boolean append)
throws FileNotFoundException;
Якщо файл не знайдений, немає закритого базового ресурсу, тому закриття його не матиме ніякої різниці. Якщо файл існує, він повинен кидати файл FileNotFoundException. Тож нічого не можна отримати, намагаючись закрити ресурс лише з цього рядка.
Причиною вам потрібно закрити файл, коли файл успішно відкрито, але згодом ви отримаєте помилку.
Давайте подивимось на наступний потік GZIPOutputStream
Є код, який може кинути виняток
private void writeHeader() throws IOException {
out.write(new byte[] {
(byte) GZIP_MAGIC, // Magic number (short)
(byte)(GZIP_MAGIC >> 8), // Magic number (short)
Deflater.DEFLATED, // Compression method (CM)
0, // Flags (FLG)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Extra flags (XFLG)
0 // Operating system (OS)
});
}
Це записує заголовок файлу. Тепер вам було б дуже незвично, ви зможете відкрити файл для запису, але не зможете написати до нього навіть 8 байт, але давайте уявити, що це може статися, і ми не закриємо файл згодом. Що відбувається з файлом, якщо він не закритий?
Ви не отримуєте жодних неочищених записів, вони відкидаються, і в цьому випадку в потоці немає жодного успішно записаного байта, який у цей момент не буферизований. Але файл, який не закритий, не живе вічно, натомість має FileOutputStream
protected void finalize() throws IOException {
if (fd != null) {
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
}
Якщо ви зовсім не закриєте файл, він все одно закриється, і не відразу (і, як я вже сказав, дані, які залишаються в буфері, втрачаються таким чином, але на даний момент їх немає)
Що є наслідком негайного закриття файлу? У звичайних умовах ви потенційно втрачаєте деякі дані, і ви потенційно не вистачаєте дескрипторів файлів. Але якщо у вас є система, де ви можете створювати файли, але ви нічого не можете написати до них, у вас є більша проблема. тобто важко уявити, чому ви неодноразово намагаєтеся створити цей файл, незважаючи на те, що ви не вдається.
І OutputStreamWriter, і BufferedWriter не кидають IOException у своїх конструкторах, тому не зрозуміло, яку проблему вони можуть викликати. У випадку BufferedWriter ви можете отримати OutOfMemoryError. У цьому випадку він негайно запустить GC, який, як ми бачили, все одно закриє файл.