为什么Try / Catch块会创建新的变量范围?

时间:2012-07-25 17:09:39

标签: java scope 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之外是如何工作的。

5 个答案:

答案 0 :(得分:49)

  

为什么在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

注意区别。 变量 p>

但是基于上面的方法名称,更有用的结构是:

SomeObject someObject = new SomeObject();
try
{
    someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod();

重新评论:

  

我想我为何为try / catch块创建了另一个范围感到困惑。

在Java中,所有块都创建范围。 if的正文,else的正文,while的正文等等 - 它们都创建了一个新的嵌套变量范围:

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

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

如果你仔细想想,那就有道理了:有些块是有条件的,比如定义ifwhile的主体。在上面的if中,bar可能已声明或未声明(取决于foo的值),这没有任何意义,因为编译器当然没有运行时值的概念foo。因此,为了保持一致性,Java的设计人员可以通过所有块创建一个新的嵌套范围。 ( JavaScript 的设计者走了另一条路 - 根本没有块范围,但是,虽然它正在被添加 - 而且这种方法会让人感到困惑。)

答案 1 :(得分:7)

在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

And Statement定义为(14.5)

Statement:
    StatementWithoutTrailingSubstatement
    LabeledStatement
    IfThenStatement
    IfThenElseStatement
    WhileStatement
    ForStatement

StatementWithoutTrailingSubstatement:
    Block
    EmptyStatement
    ExpressionStatement
    AssertStatement
    SwitchStatement
    DoStatement
    BreakStatement
    ContinueStatement
    ReturnStatement
    SynchronizedStatement
    ThrowStatement
    TryStatement

所以块,表达式语句或空语句都很好。但是声明(在第6章中定义)不在声明的语法中。

答案 2 :(得分:5)

变量或对象的范围在范围内(由花括号{}定义),其中定义了它。

因为try catch启动了一个新的作用域,可以抛出一些错误,所以try catch中定义的对象在它的作用域之外是不可用的。

答案 3 :(得分:3)

try/catch创建一个新的范围,原因很简单,它是一个块级元素。事实上,只需将{}随机放置在方法中就会创建一个新的代码块,并使用它自己的本地范围。

答案 4 :(得分:3)

每次使用括号'{'表示C ++和Java中的新范围。你试图尝试一个操作需要一些内部设置,并且确定名称允许快速跳回try块而不需要大量清理。

只要没有名称冲突(如Python),某些语言将允许您访问范围之外的那些范围变量,但这需要稍微不同的内部堆栈结构,并且仍然可能增加尝试的成本不管怎样。

此外,它只是如何在Java中定义范围定义 - 正如许多其他答案所指出的那样。