what's the point in finally?

C

Crouchez

try{
//blah }
catch(Exception ex){
// }
finally{ //do something }why not justtry{//blah}catch(Exception
e){}//do something
 
B

bugbear

Crouchez said:
try{
//blah }
catch(Exception ex){
// }
finally{ //do something }why not justtry{//blah}catch(Exception
e){}//do something

What if your exception handling code throws an Exception?

BugBear
 
E

Eric Sosman

Crouchez said:
try{
//blah }
catch(Exception ex){
// }
finally{ //do something }why not justtry{//blah}catch(Exception
e){}//do something

For one thing, the finally clause will execute no matter
how the try-ed code terminates: By throwing an Exception, by
throwing some other kind of Throwable, by return-ing or by
break-ing or by running all the way to its end -- the code
in the finally clause will be executed regardless.

Another point is that it is almost always wrong to catch
Exception: You should catch IOException or InterruptedException
or some other, more specific kind of condition (or conditions).
The code in a catch clause is supposed to "deal with" the
exceptional condition, which means you need to have anticipated
the possibility and written code expressly for that outcome. It's
just not possible to "deal" effectively with every possible kind
of Throwable, so it's pretty much a given that some kinds of
Throwable will not be caught. Would you like your cleanup code
to execute anyhow? Then put it in the finally clause.

Still another issue: Once you catch an Exception, that's the
end of the line; Java's processing of it ceases once it's caught.
So what do you do if you'd like to clean up "en passant" but
let the original Exception propagate outward to your caller?
You could re-throw the same Exception after cleaning up, or
you could wrap the caught Exception in a new Exception of your
own and throw that one instead, but both courses are clumsy.
(The second is sometimes forced upon you for other reasons.)
Put your cleanup code in the finally clause and you get exactly
the desired effect without the extra running around.
 
M

Michael Jung

bugbear said:
What if your exception handling code throws an Exception?

In fact, if you throw an exception in the finally block you have a much
toughre problem at hand. finally is used, e.g., to free resources in the good
and the bad case. Or implement some code that should be executed regardless of
whether you want the caller to get an exception or not.

Consider try blocks without catch but with finally or whithout finally but
catch.

Michael
 
C

Crouchez

Scenario A

try{
//blah
}
catch(Exception e){
}
finally{
//do something
}

why not just...

Scenario B

try{
//blah
}catch(Exception e){
}
//do something


OK right. I'm not following the arguments here. The //do something will
always be called in both scenarios unless something isn't returned in the
catch method? I don't understand why there is more use of resources either
in Scenario B? So what's the use of finally?
 
P

Patricia Shanahan

Crouchez said:
Scenario A

try{
//blah
}
catch(Exception e){
}
finally{
//do something
}

why not just...

Scenario B

try{
//blah
}catch(Exception e){
}
//do something


OK right. I'm not following the arguments here. The //do something will
always be called in both scenarios unless something isn't returned in the
catch method? I don't understand why there is more use of resources either
in Scenario B? So what's the use of finally?

In the second scenario //do something will not be called if, for
example, there was a stack overflow, because StackOverflowError does not
extend Exception.

Also consider the case in which //blah contains a return statement. Code
immediately after the try-catch-finally will not get executed. The
finally block will.

Second, catching and hiding Exception is such a dangerous thing to do
that I don't really care whether finally is or is not needed in such
code. I'm much more interested in:

try{
// blah
}
catch(SomeException e){
// Do something about it
}
catch(AnotherException e){
// Do something else
}
finally{
// Clean up after blah
}

In this, much more realistic, case there may be exceptions that do not
get caught, and with non-trivial catch blocks the catch blocks
themselves may return or throw exceptions of their own. As before, none
of the errors are being caught, and blah may contain a return statement.

Most of the very, very few gotos I wrote when I was programming in C
were substitutes for finally - situations in which there were a lot of
logical returns, but some clean-up code that had to be run on the way
out, regardless of why the function was finishing.

Patricia
 
C

Crouchez

Patricia Shanahan said:
In the second scenario //do something will not be called if, for
example, there was a stack overflow, because StackOverflowError does not
extend Exception.

are you sure? whether code throws an exception/error/throwable or not it
will still get to //do something in both scenarios. With StackOverflowError
or OutofMemoryError then the program often stops completely.
Also consider the case in which //blah contains a return statement. Code
immediately after the try-catch-finally will not get executed. The
finally block will.

Ahh i see this point. I thought return was the ultimate last in the chain -
finally does indeed get called before return but i can't think of any reason
to do that.
 
C

Crouchez

Crouchez said:
are you sure? whether code throws an exception/error/throwable or not it
will still get to //do something in both scenarios. With
StackOverflowError or OutofMemoryError then the program often stops
completely.


Ahh i see this point. I thought return was the ultimate last in the
chain - finally does indeed get called before return but i can't think of
any reason to do that.

you're right with the StackOverflowError or OutofMemoryError thing - finally
does get called. Cheers for that
 
B

bugbear

Crouchez said:
Scenario A

try{
//blah
}
catch(Exception e){
}
finally{
//do something
}

why not just...

Scenario B

try{
//blah
}catch(Exception e){
}
//do something


OK right. I'm not following the arguments here. The //do something will
always be called in both scenarios unless something isn't returned in the
catch method? I don't understand why there is more use of resources either
in Scenario B? So what's the use of finally?

In your code there is no point in finally. If you had REAL exception handling,
i.e. non empty exception blocks (which you should), the distinction
may become more obvious.

BugBear
 
P

Patricia Shanahan

Crouchez said:
are you sure? whether code throws an exception/error/throwable or not it
will still get to //do something in both scenarios. With StackOverflowError
or OutofMemoryError then the program often stops completely.

I am sure. This program:

public class StackOverflowTest {
public static void main(String[] args) {
try {
try {
badRecursion();
} catch (Exception e) {
System.out.println("Exception caught");
} finally {
System.out.println("In finally block");
}
System.out.println("After try-catch-finally");
} catch (StackOverflowError e) {
System.out.println("Caught " + e);
}
}
static void badRecursion() {
badRecursion();
}
}

prints:

In finally block
Caught java.lang.StackOverflowError

It does not reach the "After try-catch-finally" printout.

In many cases a program could in theory continue after an Error, but it
is usually not a good idea. Error implies that something is VERY wrong.

Ahh i see this point. I thought return was the ultimate last in the chain -
finally does indeed get called before return but i can't think of any reason
to do that.

finally allows you to write return statements where they logically
belong and yet be sure the method's clean-up code runs.

When I saw try-catch-finally, I knew I would not miss "goto". The few
goto's I wrote in C were all emulating a finally structure, making sure
that no matter how I completed a function I would do the cleanup.

Patricia
 
B

bugbear

Crouchez said:
Ahh i see this point. I thought return was the ultimate last in the chain -
finally does indeed get called before return but i can't think of any reason
to do that.

I suggest you go back and read Patricia's comments (and code)
after she says "I'm much more interested in: "

It's good stuff, and will help you.

BugBear
 
D

Daniel Pitts

are you sure? whether code throws an exception/error/throwable or not it
will still get to //do something in both scenarios. With StackOverflowError
or OutofMemoryError then the program often stops completely.


Ahh i see this point. I thought return was the ultimate last in the chain -
finally does indeed get called before return but i can't think of any reason
to do that.



One typical use case:
try {
return parseSomeXml();
} catch (ParserException e) {
throw new MyGenericException("Can parse xml", e);
} catch (IOException e) {
throw new MyGenericException("IO problem loading XML", e);
} finally {
cleanUpStuff();
}
 
T

Thomas Hawtin

Daniel said:
One typical use case:
try {
return parseSomeXml();
} catch (ParserException e) {
throw new MyGenericException("Can parse xml", e);
} catch (IOException e) {
throw new MyGenericException("IO problem loading XML", e);
} finally {
cleanUpStuff();
}

The trouble is that cleanUpStuff is usually declared to throw an
exception. Therefore code like that is often incorrect or messy.

My guess is that the evolution of Java went something like:

o Start with C++ where resources are flushed explicitly and destructor
do not throw. If you throw an exception from a destructor and the
destructor is called due to an exception unwinding the stack then, IIRC,
abort is called which by default calls terminate.

o This makes try-catch-finally relatively natural. I believe catch
(...) logically comes after catches with explicit exception types in
C++. I guess catch-before-finally can also allow the exception object to
depend upon the resource still being open (though generally a poor idea).

o Java goes in for virtual methods and decorators. Unfortunately
"ownership" of the resource is moved into the decorator (this would make
sense if the "decorator" create the resource from a factory rather than
being passed through the constructor).

o In order to support such decorators (buffered output streams for
example), all resources can throw exceptions when being closed. Closing
an input stream is a classic example where a close declares that it
throws an exception, but probably shouldn't.

o We are now in a situation where finally needs to be inside the try
block, but the syntax is the wrong way around.

There is also the problem that the finally block will need a reference
to the resource, even though the construction of the resource needs to
be within the try-catch.

So the general pattern should be:

try {
acquire-resource;
try {
decorate-resource;
use-decorator;
flush-decorator;
} finally {
release-resource;
}
} catch (ResourceException exc) {
... erm, do something sensible ...
... probably wrap in a different exception ...
}

Now, if the exception makes sense for the method to throw, the catch can
be removed.

With closures, such as methods within anonymous inner classes, the
common code can be factored out (although with the current syntax, you
will still end up with some highly verbose boilerplate).

Tom Hawtin
 
C

Crouchez

So...

You can't actually catch or code in a contigency plan for an
OutofMemoryError but with finally you can? because finally runs regardless
of whether an exception or error is caught or not? ie. finally always runs
if the JVM is?
 
K

kaldrenon

are you sure? whether code throws an exception/error/throwable or not it
will still get to //do something in both scenarios. With StackOverflowError
or OutofMemoryError then the program often stops completely.

public class Test
{
public static void main(String[] args)
{
try
{
return;
}
catch(Exception e){}
finally
{
System.out.println("testing");
}
}
}

Output:
"testing"
 
W

Wojtek

Crouchez wrote :
try{
//blah }
catch(Exception ex){
// }
finally{ //do something }why not justtry{//blah}catch(Exception
e){}//do something

public void myMethod() throws MyException
{
try
{
grabSomeResources();
somethingDangerous(); // throws MyException
}
finally
{
freeSomeResources();
}
}

In the above the resources will always be freed.
 
T

Thomas Hawtin

Wojtek said:
try
{
grabSomeResources();
somethingDangerous(); // throws MyException
}
finally
{
freeSomeResources();
}
}

In the above the resources will always be freed.

Even if it fails to be acquired!

The basic standard form is:

acquire; try { use; } finally { release; }.

Tom Hawtin
 
L

Lew

Crouchez said:
You can't actually catch or code in a contigency [sic] plan for an
OutofMemoryError but with finally you can? because finally runs regardless
of whether an exception or error is caught or not? ie. [sic] finally always runs
if the JVM is?

Not correct. You can catch Errors and /try/ to do something about them *in
the catch block*, just like any other Throwable. The finally block is not the
place to handle such things; the catch block is.

That said, the reason you can't effectively catch an Error is that it
represents a situation so fubared that there is no effective recovery
available. Still, you can declare a catch block to attempt to minimize the
damage.
 
T

Twisted

That said, the reason you can't effectively catch an Error is that it
represents a situation so fubared that there is no effective recovery
available. Still, you can declare a catch block to attempt to minimize the
damage.

Curiously, I'd say that StackOverflowError, at minimum, may be an
exception to this rule. I can imagine e.g.

public int myMethod (int arg) {
if (isBaseCase(arg)) return 0;
try {
return recursiveMyMethod(arg);
} catch (StackOverflowError e) {
throw new IllegalArgumentException("Argument " + arg + " to
myMethod is too big.");
}
}

The stack unwind "undoes" the damage of a stack overflow, since the
stack ends up as stubby as it was before the recursive call. Of course
the caller might still just upchuck on the IllegalArgumentException.
It's not hard to imagine a less efficient nonrecursive version of
myMethod being called, though, or some other such recovery depending
on the situation, or the result of the IAE being a particular user
operation failing without the whole app bombing.

In multithreaded parallelized code, another way to "recover" from even
OOME is to let it kill the thread it arises within. Another thread
goes to allocate something and this forces a GC, which reclaims all
the resources the now-dead thread held. Memory pressure thus leads to
scaled-back parallelization. With a control thread that holds the job
queues and has some ability to detect worker thread disappearance,
jobs can be reissued. Performance degrades instead of the task
bombing. A factory can attempt to recreate the missing worker threads
after some time has elapsed. A "fat job" could cause half the threads
to die but eventually be done with and the system would bounce back up
to its usual performance after a while.

Ultimately, how recoverable or irrecoverable any of these are is
dependent on the requirements and details of what's being implemented.

Certainly typical applications with user documents need to catch all
of them, including and especially OOME, and do a panic-save of the
user's session and unsaved data to where the next session will attempt
to recover, at minimum. (Not over the original files in case of data
corruption or other inconsistent transitional states caused by the
interrupting throwable!) To be able to do this, the exception handler
can trigger a graceful but non-memory-allocating shutdown that tells
threads to quit, destroys displayed UI, and drops references to most
objects other than those representing unsaved data, then call
System.gc() (though this should probably not be necessary), then
create some streams and save the unsaved data to the recovery file,
then pop up an apologetic error message, before shutting down. The
memory freed by first disposing of the previously-visible UI objects
alone is probably sufficient to do this successfully during exit.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top