Почему try-with-resources не работает с переменными поля?

Это мой самый первый вопрос о SO, и я смущен, что пока нет подобного вопроса!

Итак, вопрос:

почему try-with-resources не работает с переменными поля?

или другими словами: Почему для этого мне всегда нужна локальная переменная?

вот пример кода:

public class FileWriteTest {

    public FileWriter file;

    public void workingDemo() {

        try(FileWriter file = new FileWriter(new File("someFilePath")) {
            // do something
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void notWorkingDemo() {

        file = null;

        try(file = new FileWriter(new File("someFilePath")) {
            // do something
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

может кто-нибудь объяснить мне, почему эта конвенция?

6 ответов


переменная экземпляра может быть изменена в любой момент во время выполнения блока try-with-resources. Это нарушило бы его инвариант и предотвратило бы очистку. Обратите внимание, что локальная переменная неявно является окончательной по той же причине.

кстати, лучший вопрос в том, почему Java силу нам объявить локальную переменную, даже если мы не ссылаемся на нее в блоке. C#, например, не требует этого.


Я подозреваю, что дизайнеры считали использование поля плохой идеей, поскольку это позволяет объекту избежать области использования. т. е. он действителен только в блоке try, поэтому вы не сможете получить к нему доступ в другом месте.


раздел 14.20.3 на Спецификация Языка Java заявляет, что он будет работать только с локальными переменными.

Почему это? Я предполагаю, что проверка определенного назначения и эскапажа (локальная переменная не переходит в область другого метода). Поле может быть инициализировано в любом месте класса. Я предполагаю, что, проверяя локальную переменную, ее намного проще анализировать.


во-первых, я думаю, что было бы плохой практикой иметь переменную/ресурс, который используется в нескольких местах. Если он не открыт в try, то вы не можете закрыть его после этого, если он открыт там, то вам не понадобится нелокальная переменная. Это приводит к "второму": если у вас уже открыт ресурс, то вам нужно явно закрыть его где-то еще, иначе автоклоз не будет знать, открыт он или нет.

таким образом, IMHO имеет смысл обрабатывать его так, как он указывается в спецификации.


С Java 9 они добавили поддержку try с ресурсами с переменными.

    // Original try-with-resources statement from JDK 7 or 8
    try (Resource r1 = resource1;
         Resource r2 = resource2) {
        // Use of resource1 and resource 2 through r1 and r2.
    }

    // New and improved try-with-resources statement in JDK 9
    try (resource1;
         resource2) {
        // Use of resource1 and resource 2.
    }

https://blogs.oracle.com/darcy/more-concise-try-with-resources-statements-in-jdk-9


возможно, это связано с согласованностью со спецификациями языка. Всякий раз, когда переменная объявляется между двумя скобками, она инкапсулируется внутри и не может быть доступна извне:

anything
{
int var;
}

// cannot access var from here!

почему бы не попробовать { } быть исключением ?