Правильная идиома для управления несколькими связанными ресурсами в блоке 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 не будет закрыт.

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 выдает предупреждение, которое я считаю ложной тревогой, но это все еще предупреждение, с которым приходится иметь дело:

Утечка ресурсов: 'м.т.» никогда не закрывается

Итак, какой подход пойти? Или я пропустил какую-то другую идиомуправильный один?

Ответы на вопрос(8)

Ваш ответ на вопрос