112

Is it a bad practice to catch Throwable?

For example something like this:

try {
    // Some code
} catch(Throwable e) {
    // handle the exception
}

Is this a bad practice or we should be as specific as possible?

chrylis -cautiouslyoptimistic-
  • 67,584
  • 19
  • 106
  • 140
ktulinho
  • 3,402
  • 8
  • 25
  • 31
  • 5
    Related: http://stackoverflow.com/questions/581878/why-catch-exceptions-in-java-when-you-can-catch-throwables and http://stackoverflow.com/questions/2146108/which-subclass-of-throwable-should-be-caught-and-which-shouldnt – finnw May 21 '11 at 17:39

14 Answers14

106

You need to be as specific as possible. Otherwise unforeseen bugs might creep away this way.

Besides, Throwable covers Error as well and that's usually no point of return. You don't want to catch/handle that, you want your program to die immediately so that you can fix it properly.

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • 43
    There are situations where catching Error and continue is appropriate. Ex: In a servlet, if you enconter an OutOfMemoryError because a specific request happen to eat all the memory, you can try to continue since the objects will be GC after the request is handled. Same goes for an assertion error. You don't shutdown an application because something went wrong in a request. – gawi Apr 16 '13 at 01:49
  • 7
    How do you know what was allocated and what wasn't prior to the OOME? All bets are off once you get that, even inside a J2EE container like Tomcat or JBoss. – bmauter May 31 '13 at 02:05
  • 11
    We have had NoSuchMethodError and thankfully did not take out all our customers by shutting down the server as it happened two weeks after deployment. ie. We always have a catchall catching Throwable and making a best effort to handle and send error to customer. After all, there are lots of types of Error that are recoverable in that it may only affect 1 of 1000 customers. – Dean Hiller Mar 25 '15 at 21:22
  • 11
    "*you want your program to die immediately so that you can fix it properly*" => if your program dies, how do you know what happened? Catching Throwable/Error to log the problem is a reasonable thing to do... – assylias Jun 16 '15 at 09:15
  • @assylias: Only if your runtime environment doesn't already do that for some reason (e.g. badly configured stdout/logging framework). And you still need to rethrow it. – BalusC Jun 16 '15 at 09:32
  • @BalusC If you have a standalone application (`main` entry point) then it won't log anything automatically unless you ask it to do so with an uncaught exception handler or a catch-all block... Within a web or application server I agree that it it is not necessary. – assylias Jun 16 '15 at 09:34
  • 3
    @assylias A stand-alone application will throw a fatal error to stderr. – Philip Whitehouse Jan 05 '16 at 15:17
  • @BalusC +1 for your answer. Fail fast is the best approach. Do not catch Exception or Throwable. Because catching these can lead to hard to find bugs in the code. – Vadiraj Purohit May 25 '16 at 16:11
  • This is a bogus argument as there are very important reasons to catch Throwable and very important software does this: https://github.com/spring-projects/spring-framework/search?q=%22catch+%28Throwable%22&unscoped_q=%22catch+%28Throwable%22 https://github.com/apache/tomcat/search?q=%22catch+%28Throwable%22&unscoped_q=%22catch+%28Throwable%22 – Eduardo Oct 24 '18 at 05:05
  • @Eduardo: the average developer who has this question doesn't write "very important software". – BalusC Oct 24 '18 at 12:31
  • 1
    @BalusC You should reflect that in your answer. So crappy software should not catch Throwable ever, but good software can. – Eduardo Nov 03 '18 at 16:19
  • @Eduardo: No, I won't. – BalusC Nov 05 '18 at 11:24
39

This is a bad idea. In fact, even catching Exception is usually a bad idea. Let's consider an example:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
    inputNumber = 10; //Default, user did not enter valid number
}

Now, let's say that getUserInput() blocks for a while, and another thread stops your thread in the worst possible way ( it calls thread.stop() ). Your catch block will catch a ThreadDeath Error. This is super bad. The behavior of your code after catching that Exception is largely undefined.

A similar problem occurs with catching Exception. Maybe getUserInput() failed because of an InterruptException, or a permission denied exception while trying to log the results, or all sorts of other failures. You have no idea what went wrong, as because of that, you also have no idea how to fix the problem.

You have three better options:

1 -- Catch exactly the Exception(s) you know how to handle:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
    inputNumber = 10; //Default, user did not enter valid number
}

2 -- Rethrow any exception you run into and don't know how to handle:

try {
    doSomethingMysterious();
} catch(Exception e) {
    log.error("Oh man, something bad and mysterious happened",e);
    throw e;
}

3 -- Use a finally block so you don't have to remember to rethrow:

 Resources r = null;
 try {
      r = allocateSomeResources();
      doSomething(r);
 } finally {
     if(r!=null) cleanUpResources(r);
 }
Brandon Yarbrough
  • 33,119
  • 22
  • 98
  • 134
  • 4
    +1 for stating that even catching Exception is no good. At least there is an ThreadInterruptedException which requires special care (in short - after catching it, you have to set thread's interrupted status back to 'true') – Kirill Gamazkov Apr 14 '16 at 04:09
  • I Know it's just for illustrate your words but I think you can check with a regex if your user input is Alphanumeric or what format you need and don't use try catch everywhere every time. – amdev Oct 12 '16 at 13:59
  • How am I suppose to know if there's a Error/Throwable if I don't catch it? I didn't see anything in the logs. Java EE app. Just spent days stuck not knowing what the problem was until I added this catch. – Philip Rego Nov 26 '18 at 19:47
  • 2
    I consider the option #2 as bad practice. Imagine 10 chained calls with log & rethrow. If you look at the log file, you won't be happy. The exception is logged 10 times making logs very hard to read. IMHO much better is to do `throw new Exception("Some additional info, eg. userId " + userId, e);`. This will be logged in one nice exception with 10 causes. – Petr Újezdský Jun 20 '19 at 20:22
21

Also be aware that when you catch Throwable, you can also catch InterruptedException which requires a special treatment. See Dealing with InterruptedException for more details.

If you only want to catch unchecked exceptions, you might also consider this pattern

try {
   ...
} catch (RuntimeException exception) {
  //do something
} catch (Error error) {
  //do something
}

This way, when you modify your code and add a method call that can throw a checked exception, the compiler will remind you of that and then you can decide what to do for this case.

gawi
  • 13,050
  • 7
  • 38
  • 74
15

straight from the javadoc of the Error class (which recommends not to catch these):

 * An <code>Error</code> is a subclass of <code>Throwable</code> 
 * that indicates serious problems that a reasonable application 
 * should not try to catch. Most such errors are abnormal conditions. 
 * The <code>ThreadDeath</code> error, though a "normal" condition,
 * is also a subclass of <code>Error</code> because most applications
 * should not try to catch it. 

 * A method is not required to declare in its <code>throws</code> 
 * clause any subclasses of <code>Error</code> that might be thrown 
 * during the execution of the method but not caught, since these 
 * errors are abnormal conditions that should never occur. 
 *
 * @author  Frank Yellin
 * @version %I%, %G%
 * @see     java.lang.ThreadDeath
 * @since   JDK1.0
gawi
  • 13,050
  • 7
  • 38
  • 74
Andrew Norman
  • 737
  • 7
  • 21
13

It's not a bad practice if you absolutely cannot have an exception bubble out of a method.

It's a bad practice if you really can't handle the exception. Better to add "throws" to the method signature than just catch and re-throw or, worse, wrap it in a RuntimeException and re-throw.

duffymo
  • 293,097
  • 41
  • 348
  • 541
11

Catching Throwable is sometimes necessary if you are using libraries that throw Errors over-enthusiastically, otherwise your library may kill your application.

However, it would be best under these circumstances to specify only the specific errors thrown by the library, rather than all Throwables.

DNA
  • 40,109
  • 12
  • 96
  • 136
  • 13
    Or use a better written library? – Raedwald Jun 27 '13 at 07:37
  • 8
    Indeed, if you have the choice ;-) – DNA Jun 27 '13 at 07:42
  • thats the biggest problem with catching throwables and re-throwing them. it really makes an impossible interface for all the methods upstream in the stack. They either have to deal with a throwable or have an unusable throws throwable signature that others will have to deal with. – Andrew Norman Jan 27 '16 at 22:48
6

Throwable is the base class for all classes than can be thrown (not only exceptions). There is little you can do if you catch an OutOfMemoryError or KernelError (see When to catch java.lang.Error?)

catching Exceptions should be enough.

Community
  • 1
  • 1
ic3
  • 7,231
  • 8
  • 55
  • 101
5

The question is a bit vague; are you asking "is it OK to catch Throwable", or "is it OK to catch a Throwable and not do anything"? Many people here answered the latter, but that's a side issue; 99% of the time you should not "consume" or discard the exception, whether you are catching Throwable or IOException or whatever.

If you propagate the exception, the answer (like the answer to so many questions) is "it depends". It depends on what you're doing with the exception—why you're catching it.

A good example of why you would want to catch Throwable is to provide some sort of cleanup if there is any error. For example in JDBC, if an error occurs during a transaction, you would want to roll back the transaction:

try {
  …
} catch(final Throwable throwable) {
  connection.rollback();
  throw throwable;
}

Note that the exception is not discarded, but propagated.

But as a general policy, catching Throwable because you don't have a reason and are too lazy to see which specific exceptions are being thrown is poor form and a bad idea.

Garret Wilson
  • 14,167
  • 20
  • 115
  • 211
5

it depends on your logic or to be more specific to your options / possibilities. If there is any specific exception that you can possibly react on in a meaningful way, you could catch it first and do so.

If there isn't and you're sure you will do the same thing for all exceptions and errors (for example exit with an error-message), than it is not problem to catch the throwable.

Usually the first case holds and you wouldn't catch the throwable. But there still are plenty of cases where catching it works fine.

b.buchhold
  • 3,767
  • 2
  • 19
  • 33
4

Although it is described as a very bad practice, you may sometimes find rare cases that it not only useful but also mandatory. Here are two examples.

In a web application where you must show a meaning full error page to user. This code make sure this happens as it is a big try/catch around all your request handelers ( servlets, struts actions, or any controller ....)

try{
     //run the code which handles user request.
   }catch(Throwable ex){
   LOG.error("Exception was thrown: {}", ex);
     //redirect request to a error page. 
 }

}

As another example, consider you have a service class which serves fund transfer business. This method returns a TransferReceipt if transfer is done or NULL if it couldn't.

String FoundtransferService.doTransfer( fundtransferVO);

Now imaging you get a List of fund transfers from user and you must use above service to do them all.

for(FundTransferVO fundTransferVO : fundTransferVOList){
   FoundtransferService.doTransfer( foundtransferVO);
}

But what will happen if any exception happens? You should not stop, as one transfer may have been success and one may not, you should keep go on through all user List, and show the result to each transfer. So you end up with this code.

for(FundTransferVO fundTransferVO : fundTransferVOList){
    FoundtransferService.doTransfer( foundtransferVO);
 }catch(Throwable ex){
    LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
  }
}

You can browse lots of open source projects to see that the throwable is really cached and handled. For example here is a search of tomcat,struts2 and primefaces:

https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable

Alireza Fattahi
  • 33,509
  • 12
  • 96
  • 140
2

Generally speaking you want to avoid catching Errors but I can think of (at least) two specific cases where it's appropriate to do so:

  • You want to shut down the application in response to errors, especially AssertionError which is otherwise harmless.
  • Are you implementing a thread-pooling mechanism similar to ExecutorService.submit() that requires you to forward exceptions back to the user so they can handle it.
Gili
  • 76,473
  • 85
  • 341
  • 624
0

If we use throwable, then it covers Error as well and that's it.

Example.

    public class ExceptionTest {
/**
 * @param args
 */
public static void m1() {
    int i = 10;
    int j = 0;
    try {
        int k = i / j;
        System.out.println(k);
    } catch (Throwable th) {
        th.printStackTrace();
    }
}

public static void main(String[] args) {
    m1();
}

}

Output:

java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.java:25)
VicXj
  • 67
  • 6
0

Throwable is the superclass of all the errors and excetions. If you use Throwable in a catch clause, it will not only catch all exceptions, it will also catch all errors. Errors are thrown by the JVM to indicate serious problems that are not intended to be handled by an application. Typical examples for that are the OutOfMemoryError or the StackOverflowError. Both are caused by situations that are outside of the control of the application and can’t be handled. So you shouldn't catch Throwables unless your are pretty confident that it will only be an exception reside inside Throwable.

0

A more differentiated answer would be: it depends.

The difference between an Exception and an Error is that an Exception is a state that has to be expected, while an Error is an unexpected state, which is usually fatal. Errors usually cannot be recovered from and require resetting major parts of the program or even the whole JVM.

Catching Exceptions is something you should always do to handle states that are likely to happen, which is why it is enforced by the JVM. I.E. opening a file can cause a FileNotFoundException, calling a web resource can result in a TimeoutException, and so on. Your code needs to be prepared to handle those situations as they can commonly occur. How you handle those is up to you, there is no need to recover from everything, but your application should not boot back to desktop just because a web-server took a little longer to answer.

Catching Errors is something you should do only if it is really necessary. Generally you cannot recover from Errors and should not try to, unless you have a good reason to. Reasons to catch Errors are to close critical resources that would otherwise be left open, or if you i.E. have a server that runs plugins, which can then stop or restart the plugin that caused the error. Other reasons are to log additional information that might help to debug that error later, in which case you of course should rethrow it to make sure the application terminates properly.

Rule of thumb: Unless you have an important reason to catch Errors, don't.

Therefore use catch (Throwable t) only in such really important situation, otherwise stick to catch (Exception e)

TwoThe
  • 12,597
  • 3
  • 26
  • 50