tags:

views:

1091

answers:

14

Hi

We recently had a problem with a Java server application where the application was throwing Errors which were not caught because Error is a separate subclass of Throwable and we were only catching Exceptions.

We solved the immediate problem by catching Throwables rather than Exceptions, but this got me thinking as to why you would ever want to catch Exceptions, rather than Throwables, because you would then miss the Errors.

So, why would you want to catch Exceptions, when you can catch Throwables?

+30  A: 

From the Java API documentation:

The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch.

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

Errors usually are low-level (eg., raised by the virtual machine) and should not be caught by the application since reasonable continuation might not be possible.

Ferdinand Beyer
+1: If you caught VirtualMachineError, what could you possibly do next?
S.Lott
Build a new virtual machine, a faster, stronger virtual machine cos we have the technology! No wait, I agree with you. :)
cletus
You could log the message to show why the application has died.
Rob Mayhew
+4  A: 

Usually Errors are problems you cannot possibly recover from, like OutOfMemoryError. There's nothing to do by catching them, so you should usually let them escape, and bring down the virtual machine.

Craig P. Motlin
Often times I will catch Throwable in a main thread so I can catch this error in particular. There is nothing that can be done with it, but you can log it. Otherwise, you might not see the error unless you look at STDERR.
Chris Dail
And what if you don't have enough memory to log it? What good does it do you to do that?
MetroidFan2002
@MetroidFan2002: In a large number of cases you do have enough memory. For eg, if you are want to load a large file into ram, the allocation might fail. Then you can notify the user in a friendly way. But I would recommend catching OutOfMemoryError instead of Throwable in this case.
Mr. Shiny and New
@MetroidFan2002 Someone correct me if I'm wrong, but I believe the JVM (maybe only as of Java 6, not sure) reserves and guarantees a small amount of memory for logging in cases like that.
Alex Beardsley
@All. Still doesn't make good practice to catch Throwable. Depending on the nature of the application, that log might be already logged by the host system.
OscarRyz
@Nalandial: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4753347, maybe?
Michael Myers
+1  A: 

There are some good reasons here

Learning
A: 

Normally when programming, you should only catch a specific exception (such as IOException). In a lot of programs you can see a very toplevel

try {
    ...
} catch(Exception e) {
    ...
}

That catches all errors which could be recoverable and all those which indicate a bug in your code, e.g. InvalidArgumentException, NullPointerException. You can then automatically send an eMail, display a message box or whatever you like, since the JavaVM itself is still working fine.

Everything derived from Error is something very bad, you can't do anything against. The question is, if it makes sense to catch a OutOfMemoryError or a VirtualMachineError. (It is a error in the JavaVM itself, probably you can't even display a message box or send an eMail then)

You should probably not a class derived from Error, you should derive from Exception or RuntimeException.

Johannes Weiß
A: 

Slightly off topic, but you may also want to look at this very good article about exceptions.

cadrian
+6  A: 

It all depends a bit on what you're going to do with an Error once you've caught it. In general, catching Errors probably shouldn't be seen as part of your "normal" exception flow. If you do catch one, you shouldn't be thinking about "carrying on as though nothing has happened", because the JVM (and various libraries) will use Errors as a way of signalling that "something really serious has happened and we need to shut down as soon as possible". In general, it's best to listen to them when they're telling you the end is nigh.

Another issue is that the recoverability or not from an Error may depend on the particular virtual machine, which is something you may or not have control over.

That said, there are a few corner cases where it is safe and/or desirable to catch Errors, or at least certain subclasses:

  • There are cases where you really do want to stop the normal course of flow: e.g. if you're in a Servlet, you might not want the Servlet runner's default exception handler to announce to the world that you've had an OutOfMemoryError, whether or not you can recover from it.
  • Occasionally, an Error will be thrown in cases where the JVM can cleanly recover from the cause of the error. For example, if an OutOfMemoryError occurs while attempting to allocate an array, in Hotspot at least, it seems you can safely recover from this. (There are of course other cases where an OutOfMemoryError could be thrown where it isn't safe to try and plough on.)

So the bottom line is: if you do catch Throwable/Error rather than Exception, it should be a well-defined case where you know you're "doing something special".

Edit: Possibly this is obvious, but I forgot to say that in practice, the JVM might not actually invoke your catch clause on an Error. I've definitely seen Hotspot glibly gloss over attempts to catch certain OutOfMemoryErrors and NoClassDefFountError.

Neil Coffey
+1  A: 

I know it might be counter-intuitive, but just because you can catch all sorts of Exceptions and Throwables and Errors does not mean you should.

Over-aggressive catching of java.lang.Exception can lead to some serious bugs in applications - because unexpected Exceptions never bubble up, are never caught during development/testing, etc.

Best practice: only catch

  1. Exceptions that you can handle
  2. Exceptions that are necessary to catch
matt b
+1  A: 

Do NOT ever catch Throwable or Error and you should generally not simply catch a generic Exception either. Errors are generally things that most reasonable programs cannot possibly recover from. If you know what is going on, you might be able to recover from one specific error, but in that case, you should catch only that one particular error and not all errors in general.

A good reason not to catch Error is because of ThreadDeath. ThreadDeath is a fairly normal occurrence that can theoretically be thrown from anywhere (other processes like the JVM itself can generate it), and the whole point of it is to kill your thread. ThreadDeath is explicitly an Error rather than an Exception because too many people catch all Exceptions. If you ever were to catch ThreadDeath, you must rethrow it so that your thread actually dies.

If you have control over the source, it should probably be restructured to throw an Exception rather than an Error. If you don't, you should probably call to the vendor and complain. Errors should be reserved for only things that are terminal with no possible way to recover from them.

James
Never say never.
Software Monkey
This is pretty inviolable. Even if you catch just to log and rethrow, there is no guarantee that you actually have the resources to log the error, and not rethrowing is one of the most glorious ways to shoot yourself in the foot. Catch one specific error if you must, but do not catch all of them.
James
+2  A: 

I'll go a slightly different route from others.

There are many cases where you would want to catch Throwable (mainly to log/report that something evil happened).

However, you need to be careful and rethrow anything that you cannot deal with.

This is especially true of ThreadDeath.

If you ever catch Throwable, be sure to do the following:

try {
    ...
} catch (SomeExceptionYouCanDoSomethingWith e) {
    // handle it
} catch (ThreadDeath t) {
    throw t;
} catch (Throwable t) {
    // log & rethrow
}
Scott Stanchfield
Except you can't rethrow a Throwable without declaring "throws Throwable"!!
Software Monkey
No, but you can check if your Throwable instanceof Error and cast+rethrow that without declaring it. This is standard practice for ExecutionException returned from a Future.get()
noahz
and you can wrap the throwable as a runtime exception (or subclass thereof) if need be
Scott Stanchfield
A: 

This post won't make the "checked exceptions are bad" people happy. However what I am basing my answer on is how Java exceptions are intended to be used as defined by the peole that created the language.

Quick reference chart:

  • Throwable - never catch this
  • Error - indicates a VM error - never catch this
  • RuntimeException - indicated a programmer error - never catch this
  • Exception - never tach this

The reason you should not catch Exception is that it catches all of the subclasses, including RuntimeException.

The reason you should not catch Throwable is that it catches all of the subclasses, including Error and Exception.

There are exceptions (no pu intended) to the above "rules":

  • Code you are working with (from a 3rd party) throws Throwable or Exception
  • You are running untrusted code that could cause your program to crash if it thew an exception.

For the second one usually it is enough to wrap main, event handling code, and threads with the catch to Throwable and then check the actual type of the exception and deal with it as appropriate.

TofuBeer
I think you need to be a bit clearer. A NumberFormatException is a RuntimeException, and it's fairly clear that that is there to be caught...
Neil Coffey
I think he means at a higher level, since you have no idea how to recover. Catching it where you expect to see it, is all right.
sfossen
NumberFormatException is a special case... in that they likely got it wrong when they made it. However it is easy to check with a regex if it is a number or not up front as well. The general idea with Integer.parseInt is that you don't pass it bad data.
TofuBeer
Thinking a bit more about parseInt... it is acutlaly a failing of the Integer class to not have a public static boolean isInt(String) method given that NumberFormat is a RuntimeException.
TofuBeer
No, they got it right. Don't roll your own error checking with regular expressions! You'll end up with some corner case where it doesn't match the behavior of the parsing code, and the bug will be almost impossible to find. Go ahead and catch NumberFormatException, that's what it's for. Just don't do a blanket "catch RuntimeException".
rwallace
+2  A: 

There's at least one case when I think you may have to catch a throwable or a generic exception - if you're running a separate thread to perform a task, you may want to know if the "run" method of the thread has catched some exception or not. In that case, you probably will do something like this:


public void run() {
   try {
       ...
   }
   catch(Throwable t) {
       threadCompletionError = t;
   }
}

I am really not sure if it's the best approach, but it works. And I was having a "ClassNotFound" error being raised by the JVM, and it's an error and not an exception. If I let the exception be thrown, I am not sure how to catch it in the calling thread (probably there's a method but I don't know about it - yet).

As for the ThreadDeath method, don't call the "Thread.stop()" method. Call Thread.interrupt and have your thread to check if it was interrupted by someone.

Ravi Wallau
Right now answering that question and searching for documentation, I just found the static method Thread.UncaughtExceptionHandler which does that.
Ravi Wallau
But, in general, this is cleaner and more obvious; the uncaught exception handler is for when you have no control over the run() method. However, raview should mod the answer to say "There's at least one case..."
Software Monkey
I agree with SwMnk. If you design your class expecting that ClassNotFound error to be raised, then you should handle that exception inside the thread, and provide to its client a way to know something went wrong. If that happened because you didn't configure your environment properly that's PEBKAC
OscarRyz
A: 

In general it would be reasonable to try to catch Errors if only so that can be properly reported.

However, I believe there are cases when it would be appropriate to catch an Error and not report it. I'm referring to UnsatisfiedLinkError. In JAI the library uses some native libraries to implement most of the operators for performance reasons, however if the library fails to load (doesnt exist, wrong format, unsupported platform) the library will still function because it will fall back into a java only mode.

luke
A: 

There is no point in catching Error.

Errors are used to indicate something went really wrong in your application and it should be restarted.

For instance one common error is

java.lang.OutOfMemoryError

There is NOTHING you can do when that happens. Is already too late, the JVM has exhausted all its options to get more memory but it is impossible.

See this other answer to understand more about the three kinds of exceptions.

OscarRyz
I've just spent over an hour debugging an app because I forgot that an Executor will not log Errors propagated out of Runnables. My code now catches, logs and re-throws. So I disagree!
oxbow_lakes
Thanks for the comment. What was the error? Was it possible to keep your program running after that?
OscarRyz
A: 

A lot of the other answers are looking at things too narrowly.

As they say, if you are writing application code, you should not catch Throwable. You can't do anything about it, so allowing the surrounding system (JVM or framework) to handle these issues is best.

However, if you are writing "system code", like a framework or other low-level code then you may very well want to catch Throwable. The reason is to attempt to report the exception, perhaps in a log file. In some cases your logging will fail, but in most cases it will succeed and you will have the information you need to resolve the issue. Once you have made your logging attempt you should then either rethrow, kill the current thread, or exit the entire JVM.

Darron