Почему 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!
почему бы не попробовать { } быть исключением ?