Синтаксис пробного использования ресурсов Java 7 (также известный как блок ARM ( Автоматическое управление ресурсами )) хорош, короток и понятен при использовании только одного AutoCloseable
ресурса. Однако я не уверен, какова правильная идиома, когда мне нужно объявить несколько ресурсов, которые зависят друг от друга, например a FileWriter
и a, BufferedWriter
которые обертывают его. Конечно, этот вопрос касается любого случая, когда некоторые AutoCloseable
ресурсы упакованы, а не только эти два конкретных класса.
Я придумал три следующих варианта:
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()
будет вызываться дважды : не только напрямую, но и через обтекание bw.close()
.
Это не должно быть проблемой для этих двух конкретных классов, которые оба реализуют Closeable
(что является подтипом AutoCloseable
), чей контракт гласит, что close
разрешены множественные вызовы :
Закрывает этот поток и освобождает любые системные ресурсы, связанные с ним. Если поток уже закрыт, то вызов этого метода не имеет никакого эффекта.
Однако в общем случае у меня могут быть ресурсы, которые реализуют только AutoCloseable
(и не реализуют Closeable
), что не гарантирует, что их close
можно будет вызывать несколько раз:
Обратите внимание, что в отличие от метода закрытия java.io.Closeable, этот метод закрытия не обязательно должен быть идемпотентным. Другими словами, вызов этого метода close более одного раза может иметь некоторый видимый побочный эффект, в отличие от Closeable.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
Подбирает то, что происходит в кодировке файла по умолчанию - лучше быть явным.