为什么 Try/Catch 块会创建新的变量作用域?

2022-08-31 16:42:57

例如:

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/catchtry/catchExceptions


答案 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();

重新发表您的评论:

我想我对为什么甚至为尝试/捕获块创建了另一个范围感到困惑。

在 Java 中,所有块都会创建作用域。a 的主体、 a 的主体、 a 的主体等 — 它们都创建了一个新的嵌套变量作用域:ifelsewhile

if (foo) {
    SomeObject bar = new SomeObject();
}
bar.doSomething(); // <== Compilation error, `bar` is not defined

(事实上,即使是一个没有任何控制结构的块也会创建一个。

如果你仔细想想,这是有道理的:有些块是有条件的,比如定义 or 主体的块。在上面,可能已经声明了也可能没有声明(取决于 的值),这毫无意义,因为编译器当然没有运行时值的概念。因此,可能是为了保持一致性,Java的设计人员让所有块都创建一个新的嵌套范围。(JavaScript的设计者走了另一条路——尽管它被添加进来了——而且根本没有块范围——这种方法让人们感到困惑。ifwhileifbarfoofoo


答案 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 只是遵循这个成语,并强制创建一对。{ }

要响应您对未括弧的 if 语句的后续操作,请考虑:

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");
    }
}

为什么会这样,根据JLS第14章第9节,如果被定义为:

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章中定义)不在声明的语法中。