当前位置: 首页 > 知识库问答 >
问题:

为什么尝试/捕获块会创建新的变量范围?

百里杰
2023-03-14

例如:

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

共有3个答案

薛华容
2023-03-14

变量或对象的范围在其定义的范围内(由大括号{}定义)。

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

程招
2023-03-14

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

姬乐
2023-03-14

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

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

如果你仔细想想,这是有道理的:有些块是有条件的,比如定义ifwhile主体的块。在上面的if中,bar可能已经声明,也可能没有声明(取决于foo的值),这没有意义,因为编译器当然不知道foo的运行时值。所以可能为了一致性,Java的设计者同意让所有块创建一个新的嵌套作用域。(JavaScript的设计者走了另一条路

 类似资料:
  • 问题内容: 以下方法不起作用,因为内部块声明的变量与外部块中的变量同名。显然,变量属于声明它们的方法或类,而不属于声明它们的块,因此,我无法编写一个简短的临时临时块进行调试,而恰好将外部作用域中的变量压入阴影只是片刻: 我使用过的几乎每种块范围语言都支持此功能,包括我在学校为解释器和编译器编写的琐碎小语言。Perl可以做到这一点,Scheme甚至C都可以做到。甚至PL / SQL也支持这一点! J

  • 问题内容: 我只是在学习Java异常处理和Java。我制作了一个Swing GUI,用户将在两个字段中输入整数,然后单击带有算术函数的单选按钮,答案将出现在第三个文本字段中。我想包含一个try / catch块,以在用户将前两个字段之一留为空白或输入除整数以外的内容时捕获异常,以及如果用户尝试将其除以零则输入第二个catch。该窗体可以正常工作,但是不会捕获错误,只能返回堆栈跟踪并使程序崩溃。我感

  • 问题内容: 我想将一个脚本加载到redis中,该脚本将导出将来执行的脚本将依赖的函数,但是尝试定义全局函数失败,对于全局变量也是如此: 如何定义全局函数和变量? 问题答案: 查看文件scripting.c中的源代码 的doc字符串表示意图是将常见错误通知脚本作者(不使用)。 看来这不是安全功能,所以我们有两个解决方案: 可以删除此保护: 或使用:

  • 问题内容: 有没有办法在模块内部设置全局变量?当我尝试以最明显的方式进行操作(如下所示)时,Python解释器说该变量不存在。 并将模块导入其他文件后 追溯是: … UnboundLocalError:赋值之前引用了本地变量’ DBNAME ‘ 问题答案: 这是怎么回事。 首先,Python真正唯一的全局变量是模块范围的变量。您不能创建真正全局变量。您所要做的就是在特定范围内创建变量。(如果您在P

  • 所以我正在构建一个程序,从用户输入中获取int。我有一个非常简单的try/catch块,如果用户没有输入int,应该重复这个块,直到他们输入int为止。以下是代码的相关部分: 如果我为第二个整数输入一个0,那么try/catch完全按照它应该做的做,并让我再次输入它。但是,如果我有一个InputMismatchException,比如为其中一个数字输入5.5,它只是在一个无限循环中显示我的错误消息

  • 问题内容: 这将编译 这不会 我希望两者都能编译(也许这是C的工作方式?)。是什么原因导致无法在外部块中以相同的名称声明一个块中的变量? 问题答案: 简短的答案是:因为这是JLS§6.4中定义Java语言的方式。 您可能从其他语言中使用过,因此允许使用所谓的可变阴影。但是,Java语言的发明者认为这是一个笨拙的功能,他们不希望使用其语言: 此限制有助于检测其他一些非常模糊的错误。 但是,正如作者在