Почему блок Try/Catch создает новую область переменных?
Например:
try
{
SomeObject someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //can't access someObject!
Но вы можете объявить его перед блоком try/catch
, а затем он отлично работает:
SomeObject someObject;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //works fine
Мне просто интересно, почему это связано с дизайном. Почему Объекты, созданные в блоке try/catch
, не входят в область действия с остальной частью метода? Возможно, я не понимаю, как работает try/catch
, кроме того, что вы смотрите на Exceptions
.
Ответы
Ответ 1
Почему объекты, созданные в блоке try/catch, не входят в область действия с остальной частью метода?
Они есть. Переменные объявлены в блоке try/catch
не входят в область содержимого блока, по той же причине, что и все другие объявления переменных являются локальными для области, в которой они происходят: это как спецификация определяет это.:-) (Более подробно, включая ответ на ваш комментарий.)
Здесь объект, созданный внутри try/catch
, который доступен за его пределами:
SomeObject someObject = null;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); // This is fine -- unless the SomeObject
// constructor threw the exception, in which
// case someObject will be null
Обратите внимание на разницу. Там, где объявлена переменная, определяется область, в которой она существует, а не там, где был создан объект.
Но, основываясь на именах методов и т.д., более полезной структурой для этого будет:
SomeObject someObject = new SomeObject();
try
{
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod();
Ваш комментарий:
Я думаю, я в замешательстве, почему еще одна область была создана для блока try/catch.
В Java все блоки создают область. Тело if
, тело else
, a while
и т.д. — все они создают новую область вложенных переменных:
if (foo) {
SomeObject bar = new SomeObject();
}
bar.doSomething(); // <== Compilation error, `bar` is not defined
(На самом деле даже блок без какой-либо структуры управления создает его.)
И если вы думаете об этом, это имеет смысл: некоторые блоки являются условными, такими как те, которые определяют тело if
или while
. В приведенном выше if
, bar
может быть объявлен или не быть объявлен (в зависимости от значения foo
), что не имеет смысла, потому что, конечно, у компилятора нет понятия времени выполнения foo
. Вероятно, для согласованности разработчики Java пошли с наличием блоков all, создающих новую вложенную область. (Дизайнер JavaScript пошел по-другому, и не существует области блока, но, хотя он добавлен — и этот подход также смущает людей.)
Ответ 2
В Java каждый раз, когда у вас есть пара { }
, вы можете создать новую область.
Рассмотрим следующее
class ScopeTest {
public static void main(String[] args) {
int i = 0;
{ int j = 0; System.out.println(j); }
{ int j = 2; System.out.println(j); }
}
}
Try/catch просто следует этой идиоме и обеспечивает создание пары { }
.
Чтобы ответить на ваш запрос оператора без привязки, рассмотрите:
class MultiRTree {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) String s = new String("hello");
}
}
приводит к
c:\files\j>javac ScopeTest.java
ScopeTest.java:4: not a statement
if(b) String s = new String("hello");
^
ScopeTest.java:4: ';' expected
if(b) String s = new String("hello");
^
2 errors
Однако это скомпилируется просто отлично.
class ScopeTest {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) new String("hello");
}
}
Почему это так, в соответствии с разделом 9 главы 14 JLS, если он определен как:
IfThenStatement:
if ( Expression ) Statement
И выражение определяется как (14.5)
Statement:
StatementWithoutTrailingSubstatement
LabeledStatement
IfThenStatement
IfThenElseStatement
WhileStatement
ForStatement
StatementWithoutTrailingSubstatement:
Block
EmptyStatement
ExpressionStatement
AssertStatement
SwitchStatement
DoStatement
BreakStatement
ContinueStatement
ReturnStatement
SynchronizedStatement
ThrowStatement
TryStatement
Так что блок, оператор выражения или пустой оператор, это просто отлично. Но декларация (определенная в главе 6) не содержится в грамматике утверждения.
Ответ 3
Объем переменной или объекта находится в области (определяемой фигурными фигурными скобками {}), в которых он определен.
Так как try catch инициирует новую область, в которой может быть выбрана некоторая ошибка, поэтому объекты, определенные внутри try catch, недоступны вне его области.
Ответ 4
try/catch
создает новую область действия по той простой причине, что это элемент уровня блока. Фактически, простое размещение {}
случайным образом внутри метода создаст новый блок кода с его собственной локальной областью.
Ответ 5
Каждый раз, когда вы используете скобку '{', вы выражаете новую область как на С++, так и на Java. Вы пытаетесь выполнить операцию, требуя некоторой внутренней настройки и определения областей, позволяющих быстро выходить из блока try без большой очистки.
Некоторые языки позволят вам получить доступ к этим облачным переменным за пределами области действия, если не существует конфликта имен (например, на Python), но для этого требуется несколько другая внутренняя структура стека и все еще может увеличить затраты на попытку поймать независимо.
Также как только определения областей определены в Java, как указывалось многие другие ответы.