Правильная идиома для управления несколькими связанными ресурсами в блоке try-with-resources?
Java 7примерочных с-ресурсы синтаксис (также известный как блок ARM (Автоматическое управление ресурсами)) красиво, коротко и прямолинейно при использовании только одногоAutoCloseable
ресурс. Тем не менее, я не уверен, какова правильная идиома, когда мне нужно объявить несколько ресурсов, которые зависят друг от друга, например,FileWriter
и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
не будет закрыт.
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 выдает предупреждение, которое я считаю ложной тревогой, но это все еще предупреждение, с которым приходится иметь дело:
Утечка ресурсов: 'м.т.» никогда не закрывается
Итак, какой подход пойти? Или я пропустил какую-то другую идиомуправильный один?