Why can't finally{} acces in-try{} variables?

T

Timo Nentwig

Hi!

Is there any reason why I cannot do this:

try
{
final PreparedStatement st = con.prepareStatement(sql);
..
}
catch..
finally
{
if(st!=null) st.close();
}

??

I have to declare st outside of try and therefore cannot make it final
anymore. Besides I don't understand the sense why finally cannot access
variables inside try.

Can somebody explain?

Regards,
Timo
 
B

Bryan Bullard

Timo Nentwig said:
Hi!

Is there any reason why I cannot do this:

try
{
final PreparedStatement st = con.prepareStatement(sql);
..
}
catch..
finally
{
final PreparedStatement st is not in scope here.
if(st!=null) st.close();
}

??

I have to declare st outside of try and therefore cannot make it final
anymore.
possibly. why does you design require st to be final?
Besides I don't understand the sense why finally cannot access
variables inside try.
{ and } delimit scope. try-catch-finally blocks are not an exception.

-bryan
 
D

Dario

Timo said:
Hi!

Is there any reason why I cannot do this:

try
{
final PreparedStatement st = con.prepareStatement(sql);
..
}
catch..
finally
{
if(st!=null) st.close();
}

??

I have to declare st outside of try and therefore cannot make it final
anymore. Besides I don't understand the sense why finally cannot access
variables inside try.

Can somebody explain?

Because these two blocks define two different scopes.

Rewrite your code as:

PreparedStatement st = null;
try
{
st = con.prepareStatement(sql);
..
}
catch..
finally
{
if(st!=null) st.close();
}
 
F

Flip

I have to declare st outside of try and therefore cannot make it final
anymore. Besides I don't understand the sense why finally cannot access
variables inside try.

I would like to give it a shot if you don't mind. Someone else might have
another idea, but this should work.

It's the { //try code block } that's the issue. If you need the st variable
to be final, could you surround the try{}catch{}finally{} in another {}
block?
(http://java.sun.com/docs/books/tutorial/post1.0/converting/languageChanges.
html look at the New Uses for final)

I was thinking something like this.
{
final PreparedStatement st; //blank final
try
{
st = con.prepareStatement(sql);
//I believe this will work cause you can assign something to st but
only once/first time
..
}
catch{..}
finally
{
if(st!=null) st.close();
}
}
 
A

Anton Spaans

Timo Nentwig said:
Hi!

Is there any reason why I cannot do this:

try
{
final PreparedStatement st = con.prepareStatement(sql);
..
}
catch..
finally
{
if(st!=null) st.close();
}

??

I have to declare st outside of try and therefore cannot make it final
anymore. Besides I don't understand the sense why finally cannot access
variables inside try.

Can somebody explain?

Regards,
Timo

Consider this:

final PreparedStatement st; // cannot assign null since variable is final:
try {
st = con.prepareStatement(sql);
} catch (Exception) {
} finally {
// If an exception had been thrown, what is the value of st? It is
undefined.
// The thrown exception is handled before any assignment to st took
place.
// So, the statement if (st != null) can not be done.
...
}

This then would work, but st can no longer be final.
PreparedStatement st = null;
try {
st = con.prepareStatement(sql);
} catch (Exception) {
} finally {
// Now you can check if st equals null or not:
if (st != null) .....
}
 
F

Flip

final PreparedStatement st; // cannot assign null since variable is final:
try {
st = con.prepareStatement(sql);
} catch (Exception) {
} finally {
// If an exception had been thrown, what is the value of st? It is
undefined.
// The thrown exception is handled before any assignment to st took
place.
// So, the statement if (st != null) can not be done.
...
}

I don't quite understand. Why would the st not be defined in the finally
block? I thought you would be able to do a st != null check at that point
however you mentioned the throw exception is handled before assignment? But
the st var is defined outside of the try scope, I thought you would be able
to do a st != null check, no? Thanks for any heads up on this. :>
 
A

Anton Spaans

Anton Spaans said:
Consider this:

final PreparedStatement st; // cannot assign null since variable is final:
try {
st = con.prepareStatement(sql);
} catch (Exception) {
} finally {
// If an exception had been thrown, what is the value of st? It is
undefined.
// The thrown exception is handled before any assignment to st took
place.
// So, the statement if (st != null) can not be done.
...
}

This then would work, but st can no longer be final.
PreparedStatement st = null;
try {
st = con.prepareStatement(sql);
} catch (Exception) {
} finally {
// Now you can check if st equals null or not:
if (st != null) .....
}
BTW: You can not access variables declared in an inner-block from its
enclosing block or 'sibling'-blocks.

{ int i = 0; }
System.out.print(i); // compiler error;
{ System.out.print(i); // compilere error; }
 
A

Anton Spaans

Flip said:
I would like to give it a shot if you don't mind. Someone else might have
another idea, but this should work.

It's the { //try code block } that's the issue. If you need the st variable
to be final, could you surround the try{}catch{}finally{} in another {}
block?
(http://java.sun.com/docs/books/tutorial/post1.0/converting/languageChanges.
html look at the New Uses for final)

I was thinking something like this.
{
final PreparedStatement st; //blank final
try
{
st = con.prepareStatement(sql);
//I believe this will work cause you can assign something to st but
only once/first time
..
}
catch{..}
finally
{
if(st!=null) st.close();
}
}

Actually that would not work. When inside the finally { } clause, 'st' may
still be undefined. See my earliest response for the original question.
-- Anton Spaans
 
A

Anton Spaans

Flip said:
I don't quite understand. Why would the st not be defined in the finally
block? I thought you would be able to do a st != null check at that point
however you mentioned the throw exception is handled before assignment? But
the st var is defined outside of the try scope, I thought you would be able
to do a st != null check, no? Thanks for any heads up on this. :>

Hi Flip,

The variable st is not defined, only declared.
The statement:
final PreparedStatement st;
only declares the variable st. It does not define it to have some value.
This code does define it:
final PreparedStatement st = null;
But then the statement
st = con.prepareStatement(sql);
would give a compilere error (assignement to an already defined final
variable).

Try this in your code:
final int i;
int j;

System.out.println(i);
System.out.println(j);
you will see that both the println() statements will generate a compiler
error.
 
T

Timo Nentwig

Anton Spaans said:
This then would work, but st can no longer be final.

That's just it.

Maybe I should clearify my "why". I know why all this is the way it is and I
know that I can solve it by doing as you propose.

I don't know why the language was designed this way. IMO it would be quite
useful (at least much more useful than stuff like static imports in Tiger)
if I could access variables within try{} from finally{}.
 
B

Bryan Bullard

I know that, I am asking why the language was designed this way.

to enforce a structured programming model.
 
A

Anton Spaans

Timo Nentwig said:
That's just it.

Maybe I should clearify my "why". I know why all this is the way it is and I
know that I can solve it by doing as you propose.

I don't know why the language was designed this way. IMO it would be quite
useful (at least much more useful than stuff like static imports in Tiger)
if I could access variables within try{} from finally{}.

Aha, it's not so much the 'final' issue you're questioning, more the design
of the try{} catch{} finally {} design.
Your problem would not have existed if the catch{} and finally{} clauses
could be declared withIN the try{} clause, something like this:

try {
.. .... blah blah
catch(Exception e) { }
finally { }
}
 
F

Flip

The variable st is not defined, only declared.
The statement:
final PreparedStatement st;
only declares the variable st. It does not define it to have some value.
Ah, so if you just declare it, even doing a !=null will fail then? I think
I'm seeing it now.

Thanks.
 
D

Dimitri Maziuk

Bryan Bullard sez:
to enforce a structured programming model.

Bullshit. From exception handling point of view, try{} variables
_should_ be visible inside the finally{} block: the whole point
of finally{} is to clean them up.

Of course, you'd need to special-case normal scoping rules and
add more smarts to the compiler to implement that. All for the
sake of this one programmer who wants to use a final local
variable (which, AFAIK, is not even mentioned in language specs
-- nobody knows why anyone would want to do that, and nobody is
entirely sure of what it actually does). 11 out of 10 programmers
will declare relevant variables outside of try{} and everything
will work just fine.

I'd say they thought designing it the other way wasn't worth
the trouble. If they thought of it at all.

Dima
 
B

Bryan Bullard

Bullshit. From exception handling point of view, try{} variables
_should_ be visible inside the finally{} block: the whole point
of finally{} is to clean them up.

perhaps. however, scope rules must be enforced. to make such exceptions
may introduce needless ambiguities in the spec.
 
M

Mike Schilling

Timo Nentwig said:
Hi!

Is there any reason why I cannot do this:

try
{
final PreparedStatement st = con.prepareStatement(sql);
..
}
catch..
finally
{
if(st!=null) st.close();
}

??

I have to declare st outside of try and therefore cannot make it final
anymore. Besides I don't understand the sense why finally cannot access
variables inside try.

Can somebody explain?


Suppose you could access "st" in the finally block. Suppose further that
prepareStatement() throws an exception.

In the finally block, st has never been assigned to. What value does it
have? If it's null, you'll need to invent a new rule to explain why this is
true, since in every other situation in Java, accessing uninitialized
variables is illegal.
 
B

Bent C Dalager

Bryan Bullard sez:

Bullshit. From exception handling point of view, try{} variables
_should_ be visible inside the finally{} block: the whole point
of finally{} is to clean them up.

The program may pop out of the try-block into the finally-block before
a given try-block variable has been declared. Does it seem reasonable
that this try-block variable should then be visible in the
finally-block?

Cheers
Bent D
 
D

Dale King

Bryan Bullard said:
perhaps. however, scope rules must be enforced. to make such exceptions
may introduce needless ambiguities in the spec.


It really has less to do with scoping rules than it does with definite
assignment. Definite assignment says that a local variable must be
definitely assigned a value before its value is accessed. Sun considers this
so important that they devoted an entire chapter of the Java Language
Specification to the subject:

http://java.sun.com/docs/books/jls/second_edition/html/defAssign.doc.html#25
979

If a variable is declared inside a try block there is no way to know if the
variable was definitely assigned or not. The JLS requires that a compiler be
quite conservative in its flow analysis, which would mean for the try block
to assume that an exception could occur anywhere in a try block. The only
way out is to definitely assign a value outside of the try block and then
you know it was definitely assigned a value in a catch or finally block.
Since we have such conservative definite assignment rules, it is convenient
to enforce them with scoping rules.

But the important thing is that the motivation is definite assignment, not
the scoping rules.
 
D

Dimitri Maziuk

Bent C Dalager sez:
The program may pop out of the try-block into the finally-block before
a given try-block variable has been declared. Does it seem reasonable
that this try-block variable should then be visible in the
finally-block?

Actually, it's not so unreasonble: just because the language
allows you to declare a variable anywhere in the source code
doesn't mean that's how it really works in the executable.
And you could check if variable is undefined, too. It's not
exactly rocket science, e.g. Perl does that.

But that's not the point. My point was: the purpose of finally{}
is to clean up resources allocated in try{}. So how TF am I
supposed to do that if I can't get to those variables?

Dima
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top