Подтвердить что ты не робот

Почему блок 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.

4b9b3361

Ответ 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, как указывалось многие другие ответы.