Why does a Try/Catch block create new variable sco

2019-01-03 15:46发布

For example:

try
{
    SomeObject someObject = new SomeObject();
    someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //can't access someObject!

But you can declare it before the try/catch block and then it works fine:

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

I'm just wondering the design reason for this. Why are Objects created within the try/catch block not in scope with the rest of the method? Maybe I'm not understanding deep down how a try/catch works besides just watching for Exceptions thrown.

5条回答
啃猪蹄的小仙女
2楼-- · 2019-01-03 16:27

In Java, any time you have a { } pair, you can create a new scope.

Consider the following

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); }
    }
}

The try/catch just follows this idiom, and enforces a { } pair to be created.

To respond to your followup of a non-bracketed if statement, consider:

class MultiRTree {
    public static void main(String...args) {
        boolean b = args.length == 0;
        if(b) String s = new String("hello");
    }
}

results in

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

However, this will compile just fine.

class ScopeTest {
    public static void main(String...args) {
        boolean b = args.length == 0;
        if(b) new String("hello");
    }
}

Why this is so, according to the JLS Chapter 14, section 9, if is defined as:

IfThenStatement:
    if ( Expression ) Statement

And Statement is defined as (14.5)

Statement:
    StatementWithoutTrailingSubstatement
    LabeledStatement
    IfThenStatement
    IfThenElseStatement
    WhileStatement
    ForStatement

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

So a block, expression statement, or empty statement those are just fine. But a declaration (defined in chapter 6) is not in the grammar of statement.

查看更多
▲ chillily
3楼-- · 2019-01-03 16:36

Why are Objects created within the try/catch block not in scope with the rest of the method?

They are. Variables declared within the try/catch block are not in scope in the containing block, for the same reason that all other variable declarations are local to the scope in which they occur: That's how the specification defines it. :-) (More below, including a reply to your comment.)

Here's an object created within a try/catch which is accessible outside of it:

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

Note the difference. Where the variable is declared defines the scope in which it exists, not where the object was created.

But based on the method names and such above, the more useful structure for that would be:

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

Re your comment:

I guess I'm confused as to why another scope has even been created for a try/catch block.

In Java, all blocks create scope. The body of an if, the body of an else, of a while, etc. — they all create a new, nested variable scope:

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

(In fact, even a block without any control structure creates one.)

And if you think about it, it makes sense: Some blocks are conditional, like the one defining the body of an if or while. In the above if, bar may or may not have been declared (depending on the value of foo), which makes no sense because of course the compiler has no concept of the runtime value of foo. So probably for consistency, the designers of Java went with having all blocks create a new nested scope. (The designer of JavaScript went the other way — there is no block scope at all, yet, though it's being added — and that approach also confuses people.)

查看更多
趁早两清
4楼-- · 2019-01-03 16:41

try/catch creates a new scope for the simple reason that it is a block level element. In fact, simply placing {} just randomly inside a method will create a new block of code with it's own local scope.

查看更多
Ridiculous、
5楼-- · 2019-01-03 16:44

The scope of a variable or object is in the scope (defined by curly braces {}) in which it is defined.

Since try catch initiates a new scope where some error can be thrown so the objects defined inside try catch are not available outside it's scope.

查看更多
姐就是有狂的资本
6楼-- · 2019-01-03 16:44

Every time you do use a bracket '{' you're expressing a new scope in both C++ and Java. You're attempt to try an operation requires some internal setup and scoping the names allows for quick jumps back out of the try block without a lot of cleanup.

Some languages will let you access those scoped variables outside of the scope as long as there isn't a name conflict (like in Python), but this requires an slightly different internal stack structure and could still increase the costs of the try catch regardless.

Also it's just how scope definitions are defined in Java -- as many of the other answers pointed out.

查看更多
登录 后发表回答