Monday, July 26, 2021

Why Catching Throwable or Error is bad?

We often hear advice that catching Throwable or Error is bad practice and Java developer should avoid catching these, but have you thought Why? If the language allows you to catch anything which is an instance of java.lang.Throwable, then what is the problem of catching them or their subclass java.lang.Error? If they are bad, shouldn't Java itself has prohibited them from catching?  Well, this all looks good on theory, but not in real-world programming. As I said before in Java Exception best practices post, Ideally you should never catch Throwable or in particular Error. There are several reasons why catching an instance of java.lang.Throwable is a bad idea because in order to catch them you have to declare at your method signature e.g. public void doSomething() throws Throwable.

When you do this, nobody knows what kind of Error this method is going to throw, and until you know what is the problem, how can you resolve that. The main purpose of providing Exception handling mechanism is to handle error situation properly, but you can't a provide a solution which can solve all problems.

That's why we have specific Exception classes e.g. FileNotFoundException, IllegalArgumentException, IOException and so on. So if you don't know how to resolve or handle the error, there is no point catching Throwable, all it make your code hard to read and comprehend.

Remember, each error handling code is driven by business/audit/reporting or quality requirement and catching Throwable just obscures those logics.

Some programmer catches Throwable and re-throw it by wrapping it into RuntimeException. Catching and re-throwing Exception after logging is OK but you must not rewrap the exception in a RuntimeException, and if you do make sure to preserve actual cause and stack-trace.



Spring framework does lot of this checked to unchecked exception conversion, which makes your code free of boiler-plate but also posses challenge when you are going to debug any problem. When Spring framework prints stack trace for any issue, they are usually very long, combination of multiple exception and their cause, which actually buries the real issue down in the log file. If you are not careful, you may spend countless hours fixing bug at wrong place.

Should you Catch Throwable, Exception or Error
Similarly Error covers system exceptions that you can't do anything about and should let show up (for instance OutOfMemoryError, StackOverFlowError, ThreadDeath). Rethrowing them as a unchecked exception hides them and doesn't help the cause. It may even prevents handlers that really know how to deal with them, from seeing them. That's why code catching java.lang.OutOfMemoryError is of no use, apart from giving false impression to developer that by catching OutOfMemoryError and calling System.gc() may help Application to come out of the memory mess they have created.

Catching Exception is nearly as bad as catching Throwable. Exception covers all kinds of exceptions ranging from NullPointerException to  InterruptedException, which should never be caught lightly. If you think you are actually coding same handling logic for multiple exception e.g. FileNotFoundException or IOException, consider using JDK 7 improved Exception handling feature, which allows you to catch multiple Exceptions in same catch block. Benefit of using multi-catch block over catching Exception is, it is explicit, more readable and only catch what is required, and not masking other programming errors.

By the way, in real-world, there are Exceptions :), Yes Exception on catching Throwable. There are cases, where you need to catch Throwable e.g. if an application has a requirement of constantly running and never going off, no matter what happens.

In data-driven and even based system, e.g. an order processing engine, if your system failed to process one order due to any exception, it should continue with next order to keep impact only with that order.

Now catching Throwable provides you a safety net to catch anything which you have not excepted. Though this will not help you if your system is out of resources e.g. running out of memory, or running out of thread, it does prevent you from data errors, e.g. Encoding related issues,  and several others, which you have not thought about.

By the way, if you catch Throwable, use it as a safety net, not as your primary exception handling code, and make sure to evolve and improve your exception handling code, as and when your safety net exposes new Exceptions. Let me know what is your thought on catching Error or Throwable? Have you ever catch Throwable in real-world applications, and what did you learn from that.


7 comments:

  1. I'm sure there's a better way to do this but in android there are certain times when the user may be on an edit screen which causes the soft keyboard to show. If he then navigates to another screen with no edit text the keyboard will stay on the screen. So as a programmer I may tell the screen to hide always hide the keyboard. But it the user is coming from a screen that doesn't make the soft keyboard show when he navigates to the screen that hides the keyboard some devices will throw a null point exception because in that case I'm trying to hide a keyboard that doesn't exist. So I just catch the exception since I already know what the reason is. Probably bad...I know.

    ReplyDelete
  2. Hello Craig, I agree with you, sometime to keep application running, you got to something like that, but that should be the last thing to do. I have seen code, where programmer catching SQLException, instead of fixing code, because null value for that variable is permitted and they know that it doesn't exist in database. I mean, many programmer think there job done by catching Throwable/Exception/Error, now program will not crash, this is where it turns bad.

    ReplyDelete
  3. Your example on multicatching is a bit poorly chosen as FileNotFoundException is a subclass of IOException. In this case it is enough to catch IOException as that one will also catch FNFE.

    The multicatch is ofcourse a nice way to avoid boilerplating multiple exceptions of a different type.

    ReplyDelete
  4. @Javin Nice article , Just want to add..Probably the most important one is, never swallow a checked exception. By this I mean don't do this:

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

    unless that's what you intend. Sometimes people swallow checked exceptions because they don't know what to do with them or don't want to (or can't) pollute their interface with "throws Exception" clauses.

    If you don't know what to do with it, do this:

    try {
    ...
    } catch (IOException e) {
    throw new RuntimeException(e);
    }

    ReplyDelete
  5. @Javin another est practices we can have for example as shown below..
    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);
    }

    ReplyDelete
  6. I completely agree on catching Exception and Throwable are bad, but IMHO I believe there is one particular situation where they could be useful (provided logging and stacktrace are preserved) : serving web pages. Catching a generic Exception/Throwable is bad in pretty much every layer of software, except at the outer most one serving web page. In context of serving pages, it may be cleaner to catch the Throwable, log the error and redirect somewhere (custom error page/homepage or something more specific). However, API calls that are used by the UI or other services should throw errors back with no handling.
    My 2 cents.

    ReplyDelete
  7. you need to catch Throwable in worker threads else when all worker threads will be died, no work will be done by app (event processing or application processing). however, incase of error, never catch because even if you do or call System.gc() in outOfMemory case not necessary it will help instead of that app should be stopped once come to know that there is 0 event processing

    ReplyDelete