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
,telse
、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