Why catch specific exceptions

F

Frank Cisco

Why not wrap everything around 'throws Throwable' and
'try{...}catch(Throwable t)' then deal with the error by catching it and
dealing with each case with instanceof?
 
K

Karl Uppiano

Frank Cisco said:
Why not wrap everything around 'throws Throwable' and
'try{...}catch(Throwable t)' then deal with the error by catching it and
dealing with each case with instanceof?

Declaring everything throws Throwable simply says that something bad might
happen, but I'm not telling you what it is. You have to guess. It compiles,
but it isn't very helpful to the eventual consumers of your method.

As for catching Throwable and using instanceof to sort it all out, consider
this (13 lines)...

try {
....
} catch (Throwable t) {
if(t instanceof IOException) {
// cleanup I/O problem
} else if (t instanceof NullPointerException) {
// cleanup NPE problem
} else if (t instanceof IllegalArgumentException) {
// cleanup IAE problem
} else if (t instanceof Throwable) {
throw t; // can't handle it -- rethrow
}
}

....vs. this (nine lines)...

try {
....
} catch (IOException ioe) {
// cleanup I/O problem
} catch (NullPointerException npe) {
// cleanup NPE problem
} catch (IllegalArgumentException iae) {
// cleanup IAE problem
}

.... same logic.
 
T

Tom Anderson

Declaring everything throws Throwable simply says that something bad might
happen, but I'm not telling you what it is. You have to guess. It compiles,
but it isn't very helpful to the eventual consumers of your method.

As for catching Throwable and using instanceof to sort it all out, consider
this (13 lines)...

try {
...
} catch (Throwable t) {
if(t instanceof IOException) {
// cleanup I/O problem
} else if (t instanceof NullPointerException) {
// cleanup NPE problem
} else if (t instanceof IllegalArgumentException) {
// cleanup IAE problem
} else if (t instanceof Throwable) {
throw t; // can't handle it -- rethrow
}
}

...vs. this (nine lines)...

try {
...
} catch (IOException ioe) {
// cleanup I/O problem
} catch (NullPointerException npe) {
// cleanup NPE problem
} catch (IllegalArgumentException iae) {
// cleanup IAE problem
}

... same logic.

And if you want to use any class-specific features of the exception, like
calling getSQLState() on an SQLException, you have to add a cast inside
the instanceof, so that's yet another line.

tom
 
L

Lew

Tom said:
And if you want to use any class-specific features of the exception,
like calling getSQLState() on an SQLException, you have to add a cast
inside the instanceof, so that's yet another line.

I don't know how much use there is counting lines (it's only typing and
reading, after all), but separate catch blocks allow at least two useful
things. First, one can tailor the response if only the wording of the log
message (you *are* logging exceptions, right?), as well as the kind of
exception-specific logic Tom mentioned. Second, catching 'Throwable' or even
'Exception' is a bad practice, in part for the reasons Pete mentioned.

There is at least one fundamental dichotomy in handling the 'Exception'
hierarchy, checked vs. unchecked exceptions. Loosely speaking, runtime
exceptions represent programmer error and checked exceptions represent
environmental issues like an I/O failure. That argues for two different kinds
of handling right there. Anything outside of 'Exception' types, namely
'Error' and other 'Throwable' tosses, is usually such a huge fubar as to
require application shutdown.

We should not look at programs only through the lens of initial authorship.
By definition, successful programs will spend much more time in maintenance
cycle than in development cycle. Going through the very, very effortless step
of adding a few extra stanzas of 'catch' block document the code and provide
evidence of the author's thoughtful attention, both priceless for maintainers.
Conversely, a 'catch ( Throwable thr )' evidences a sloppy, lazy author and
raises red flags for maintainers, and does nothing to document the situations
the program expects to find.

That said, in production systems a final 'catch ( Exception exc )' after the
explicit catches can sometimes help a production system with rigid uptime
requirements by allowing logging of unexpected programmer errors (it should
only ever catch 'RuntimeException' occurrences in practice) and continued
application action. Of course, it's also dangerous to continue to run an app
that has just proven itself buggy.

There's generally no point to continuing to run an app after hitting an
'Error' or other non-'Exception' 'Throwable' (after logging the problem and
notifying the console, it goes without saying).
 
S

Seamus MacRae

Lew said:
I don't know how much use there is counting lines (it's only typing and
reading, after all), but separate catch blocks allow at least two useful
things. First, one can tailor the response if only the wording of the
log message (you *are* logging exceptions, right?), as well as the kind
of exception-specific logic Tom mentioned. Second, catching 'Throwable'
or even 'Exception' is a bad practice, in part for the reasons Pete
mentioned.

One place where it's still nigh-unavoidable though is in code that
returns a stream, or similar, after doing something with it first.
Generally, if there's any exception -- any at all -- you want to close
the stream if it was opened and then propagate the exception. But you
don't want to do so on success, so closing the stream in a finally block
is a bad idea. The current only way out of this is ugly: set a boolean
success flag to false, open the stream, enter the try block, in the last
line of the try block set the flag to true, and in the finally block
test the flag to decide whether to close the stream.

Catching Throwable, closing the stream, and rethrowing works, but forces
you to declare "throws Throwable".

Java 7 should fix this with

catch (final Throwable e) {
s.close();
throw e;
}

not requiring you to declare "throws Throwable", just whatever checked
exception types could have been thrown in the try block (and aren't
handled elsewhere in the method).

But a cleaner fix would be if something (Java 8?) added an onerror keyword:

try {
// Stuff that might throw
} catch (Ex1 e) {
// Deal with Ex1s
} catch (Ex2 e) {
// Deal with Ex2s
} onerror {
// Do this on any exception, after any catches execute
} finally {
// Do this after try block, any catches, and possibly onerror
// execute.
}

Another option would be to add an "iferror {...}" that could only appear
in finally blocks and that ran only if there was an exception being
propagated during stack unwinding, or an "iserror" boolean value that
evaluated to true if there was an exception raised and not yet handled.
The latter might even be used outside finally -- the close method of
stream could avoid ever clobbering a pre-existing exception by not ever
throwing IOException if iserror, for example.
 
R

Roedy Green

Why not wrap everything around 'throws Throwable' and
'try{...}catch(Throwable t)' then deal with the error by catching it and
dealing with each case with instanceof?

then there is no guarantee you have handled everything at the lowest
possible level.
--
Roedy Green Canadian Mind Products
http://mindprod.com

If everyone lived the way people do in Vancouver, we would need three more entire planets to support us.
~ Guy Dauncey
 
R

Roedy Green

Java 7 should fix this with

catch (final Throwable e) {
s.close();
throw e;
}

would you not handle that particular case with finally?
--
Roedy Green Canadian Mind Products
http://mindprod.com

If everyone lived the way people do in Vancouver, we would need three more entire planets to support us.
~ Guy Dauncey
 
R

Roedy Green

Why not wrap everything around 'throws Throwable' and
'try{...}catch(Throwable t)' then deal with the error by catching it and
dealing with each case with instanceof?

There is a value is conformity in writing computer code. You don't
want to be entertaining, original etc just for the fun of it. The
more stereotypical your code is, the easier it will be for others to
follow.

People don't READ your code, they IGNORE it, they SKIM it. There is
way, way too much of it to read line by line. You need to write your
code to make it easy for others to say to themselves "nothing funny
going on there" and whip on to the next hunk.
--
Roedy Green Canadian Mind Products
http://mindprod.com

If everyone lived the way people do in Vancouver, we would need three more entire planets to support us.
~ Guy Dauncey
 
J

Joshua Cranmer

Frank said:
Why not wrap everything around 'throws Throwable' and
'try{...}catch(Throwable t)' then deal with the error by catching it and
dealing with each case with instanceof?

1. You lose compile-time type safety.
2. This may be a bit of micro-optimization, but you less a lot of
performance.
3. You also negate the purpose of checked exceptions--it forces you to
think about what would happen in circumstances. If methods only declare
"throws Throwable", you don't know if they could be throwing
IOExceptions, SQLExceptions, or
OurMassiveDatabaseConnectionJustCrashedAndBurnedExceptions. You end up
with a catch-all which would probably be wrong.
 
A

Arved Sandstrom

Roedy said:
would you not handle that particular case with finally?

The intent of this semantics is that the catch block, when it rethrows
e, is only throwing checked exceptions in the try block. Point being is
that you do occasionally want to cast a wide net with that catch.

Using "finally" would defeat the purpose - you'd always be executing
that code.

AHS
 
C

Chris Riesbeck

Roedy said:
People don't READ your code, they IGNORE it, they SKIM it. There is
way, way too much of it to read line by line. You need to write your
code to make it easy for others to say to themselves "nothing funny
going on there" and whip on to the next hunk.

A phrase I've used is "short attention span programming" (inspired by
the old Comedy Channel show "Short Attention Span Theater). Assume
future maintainers of your code have no patience at all.
 
F

Frank Cisco

But catching throwable almost guarantees that everything is caught - even
the runtime stuff the compiler doesn't know about? Better to catch the error
than let jvm catch it?
 
J

Joshua Cranmer

Frank said:
But catching throwable almost guarantees that everything is caught - even
the runtime stuff the compiler doesn't know about? Better to catch the error
than let jvm catch it?

It depends on the error. Handling OutOfMemoryError is probably not
recommended, nor is ThreadDeath. InternalError probably has too little
context to know what to do as well. Now, stuff like VerifyError may be
helpful in certain contexts, mostly involving the most advanced forms of
runtime class manipulation. For the most part, though, *Error is beyond
the capability of most applications to appropriately handle.

RuntimeException is another class of topics; catching stuff here might
or might not be advisable depending on the situation.
 
K

Karl Uppiano

Frank Cisco said:
But catching throwable almost guarantees that everything is caught - even
the runtime stuff the compiler doesn't know about? Better to catch the
error than let jvm catch it?

An unhandled exception is only a bad thing when you *should* have handled
it. If you don't know what to do with it once you catch it, best to let it
fly.
 

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,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top