Правильная идиома для управления несколькими связанными ресурсами в блоке try-with-resources?

Java 7try-with-resources синтаксис (также известный как блок ARM (Automatic Resource Management)) красиво, коротко и прямолинейно при использовании только одного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 will not be closed.

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() will be called twice: не только напрямую, но и через упаковкуbw.close().

Это не должно быть проблемой для этих двух конкретных классов, которые оба реализуютCloseable (который является подтипомAutoCloseable), чей контракт гласит, чтоclose разрешены:

Closes this stream and releases any system resources associated with it. If the stream is already closed then invoking this method has no effect.

Однако в общем случае у меня могут быть ресурсы, которые реализуют толькоAutoCloseable (и неCloseable), который не гарантирует, чтоclose можно вызвать несколько раз:

Note that unlike the close method of java.io.Closeable, this close method is not required to be idempotent. In other words, calling this close method more than once may have some visible side effect, unlike Closeable.close which is required to have no effect if called more than once. However, implementers of this interface are strongly encouraged to make their close methods idempotent.

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

Resource leak: 'bw' is never closed

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

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

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