Why does a Try/Catch block create new variable scope?
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.)
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.
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.
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.
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.