Why Aren't Variables Declared in "Try" in Scope in "Catch" or "Finally"

Why aren't variables declared in try in scope in catch or finally?

Two things:

  1. Generally, Java has just 2 levels of scope: global and function. But, try/catch is an exception (no pun intended). When an exception is thrown and the exception object gets a variable assigned to it, that object variable is only available within the "catch" section and is destroyed as soon as the catch completes.

  2. (and more importantly). You can't know where in the try block the exception was thrown. It may have been before your variable was declared. Therefore it is impossible to say what variables will be available for the catch/finally clause. Consider the following case, where scoping is as you suggested:


    try
    {
    throw new ArgumentException("some operation that throws an exception");
    string s = "blah";
    }
    catch (e as ArgumentException)
    {
    Console.Out.WriteLine(s);
    }

This clearly is a problem - when you reach the exception handler, s will not have been declared. Given that catches are meant to handle exceptional circumstances and finallys must execute, being safe and declaring this a problem at compile time is far better than at runtime.

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.)

Why can't I access variables inside a try/catch block?

You have to bring them outside, because otherwise the variable exists only within the try block. But this is an improvement. If you change your code to this:

Reader reader = new FileReader("/my/file/location");
try {
//Read the file and do stuff
} catch(IOException e) {
e.printStackTrace();
} finally {
reader.close();
}

then the code in the try-block, including the finally, can all rely on the reader having been created successfully. Otherwise, in your example, if the instantiation fails your code still tries to close the reader, which will still be null, on the way out.

In this changed example the exception thrown by the instantiation of the reader doesn't get handled by the catch block.

A combination of problems led you here, one is you're more worried about trying to squash all the exceptions with one catch block than you are about making sure the reader is in a valid state before you start calling methods on it. (You'll see this one-try-block-to-rule-them-all style a lot in JDBC code where people just can't bear to write all the nested try blocks, it's too ugly to tolerate.) Also, it's very toy-example-ish to catch all the exceptions locally like this, in real life if something goes wrong you want to let the exception be thrown so the rest of the application can know something went wrong, giving you something like

public void doStuffWithFile() throws IOException {
Reader reader = new FileReader("/my/file/location");
try {
//Read the file and do stuff
} finally {
try {
reader.close();
} catch (IOException e) {
// handle the exception so it doesn't mask
// anything thrown within the try-block
log.warn("file close failed", e);
}
}
}

which is very similar to what try-with-resources does. try-with-resources creates the objects first, then executes the try block, then closes the things it created, making sure that any exception thrown on close does not mask an exception thrown in the try-block. Creating the objects still has the potential to throw an exception, it doesn't get handled by the try-with-resources.

public void doStuffWithFile() throws IOException {
try (Reader reader = new FileReader("/my/file/location")) {
//Read the file and do stuff
}
}

PHP variable scope within Try/Catch block

Your code is valid. Variable scope in PHP is by function, not block. So you can assign a variable inside the try block, and access it outside, so long as they're in the same function.

Using a variable in a try,catch,finally statement without declaring it outside

Python does not have block scope. Anything defined inside the try block will be available outside.

That said, you would still have a problem: if it is the getConnection() call that raises the error, cursor will be undefined, so the reference in the finally block will error.

How to make final variables declared in a try block to be used in catch / finally block?

Since Java 7, you can write things like that:

public StringBuffer readFile(final File inputFile) {
String tempLine; // variable declaration
Logger log = Logger.getLogger("Error Message");
final StringBuffer content = new StringBuffer();
try (final FileReader fileReader = new FileReader(inputFile);
final BufferedReader bufferedReader = new BufferedReader(fileReader)){
while((tempLine=bufferedReader.readLine())!=null) {
content.append(tempLine);
content.append(System.getProperty("line.separator"));
}
}
catch(FileNotFoundException e) {
log.log(Level.WARNING, "File not found", e);
}
catch (IOException e) {
log.log(Level.WARNING, "Couldn't Read file", e);
}
return content;
}

Here fileReader and bufferedReader are implicitly closed.

Variable not initialized in try catch block `finally`

If you print variable 'i' in catch block before initialization, it gives error because compiler thinks that an exception might be thrown before 'i' has been set in try block in which case 'i' would not have been initialized so is the case with finally here i.e. when you print 'i' in finally block compiler thinks that an exception might be thrown before 'i' has been set in catch block in which case 'i' would not have been initialized

Compiler doesn't understand that the variable is initialized in either the try or the catch block. Compiler complains because local variables should be declared and initialized at the same time but you have just declared it. If you use it in either block (try, catch, finally) without initialization compiler complain about it. Try it:

    int i;
try {
System.out.println(i);
//i = 0;
}
catch (Exception e) {
System.out.println(i);
//i = 2;
}
finally {
System.out.println(i);
}

In C#, why is a variable not definitely assigned at the beginning of a finally block?

Simple reason is - There is no guarantee that the code in try or catch block will ever execute, before finally block.

ThreadAbort Exception can happen inside the try block, but before assignment executes.

Runtime code executes after exception is thrown but before code in catch blocks executes (Search for how exception handling works in .Net or "Structured Exception Handling").

Hence, code in try and catch block may never execute, before execution of finally block.

Local variable unassigned issue using Try, catch, finally

Change :

int number;
string sqrt;

Update :

double number = 0.0;
string sqrt = string.Empty;


Related Topics



Leave a reply



Submit