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

Java 为什么Try/Catch块会创建新的变量范围?,java,scope,try-catch,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

例如:

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
是如何工作的

为什么在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
的主体、
while
的主体等-它们都创建了一个新的嵌套变量范围:

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

bar.doSomething();// 变量或对象的范围在其定义的范围内(由大括号{}定义)


由于try-catch会启动一个新的作用域,其中可能会抛出一些错误,因此try-catch中定义的对象在其作用域之外不可用。

在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节,if定义为:

IfThenStatement:
    if ( Expression ) Statement
该声明定义为(14.5)


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

try/catch
创建了一个新的范围,原因很简单,它是块级元素。事实上,只要将
{}
随机放置在一个方法中,就会创建一个具有自己局部作用域的新代码块。

每次使用括号{你在C++和java中都表达了一个新的范围。你尝试一个操作需要一些内部设置,并且对这些名称进行范围化,允许在没有大量清理的情况下快速跳出尝试块。

一些语言允许您访问范围外的变量,只要不存在名称冲突(如Python中),但这需要稍微不同的内部堆栈结构,并且仍然可能增加try-catch的成本


此外,正如许多其他答案所指出的那样,这也是Java中如何定义范围定义的问题。

请告诉我!这个范围是为了防止抛出异常(即使在声明的对象的构造函数中也是如此)。如果try从未到达该实例化语句,我们就无法继续使用该对象。我想我对为什么为try/catch块创建了另一个作用域感到困惑。我想他知道它是如何工作的;相反,他是在问为什么决定这样做。@Atlos:因为在Java中,所有块都创建作用域。
if
,t
else
while
等的主体都创建了自己的变量范围。这就是语言的定义方式。它的优点是可以更接近使用它们的地方声明内容;缺点是这样做会导致编写长函数,而实际上应该将它们分解为子函数s、 :-)@T.J.Crowder这比保持所有块的一致性更有意义。如果我想让抛出异常的方法给它赋值,然后在其他地方使用它,我发现在块之外声明我的所有变量是很乏味的。我想这是没有办法的。Java中的每个块都定义了一个新的作用域。N不要只是尝试块。不遵循一般规则会非常不一致。如果您有一个
if
语句,其中没有使用
{}
对,比如
if(true)SomeObject SomeObject=new SomeObject()
,是否
someObject
在方法的作用域内,或者编译器是否为我插入了隐含的括号?@Atlos-它做了一些尴尬的事情。可以说,它是不允许的!我将在中编辑它。基本上,
newsomeobject();
是允许的,因为它是一个语句,但是
someObject so=newsomeobject()
是不允许的,因为它是一个声明(即使其中包含一条语句)。
Statement:
    StatementWithoutTrailingSubstatement
    LabeledStatement
    IfThenStatement
    IfThenElseStatement
    WhileStatement
    ForStatement

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