例如:
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
之外是如何工作的。
答案 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
(事实上,即使是没有任何控制结构的块也会创建一个。)
如果你仔细想想,那就有道理了:有些块是有条件的,比如定义if
或while
的主体。在上面的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中定义范围定义 - 正如许多其他答案所指出的那样。