Ten practices for perfect Java Exception handling

5.  “Recovering from exceptions” should be done rarely, if at all

Your system has suffered a runtime exception.

Your system has suffered a runtime exception.

Most code shouldn’t try and recover from exceptions. If you can’t prove that business outputs will be 100% correct, it’s generally best just to fail.

There are a couple of situations where exceptions can correctly be caught and handled.

1.  Parsing — when a missing/ invalid input can be ignored.
2.  “Business contingency” — exceptions indicating a business outcome other than success; such as InsufficientFundsException. These should result in a different process/ execution flow.

High-reliability software may also attempt to skip or retry failed subsystems, in some select situations:

3.  Optional subsystems — eg. a printer, which might not be required right now to complete the business process.
4.  Retry unreliable subsystems — retry may be used for unreliable systems/ connections. It is also common when obtaining locks against concurrent (multi-user) databases.

Retry & fault-recovery code is complex, and creates the possibility of pathological interactions (flooding, loops, log flooding, overloading a failing subsystem). This creates it’s own potential for error — I have seen Oracle crash due to faults in “recovery” code.

Generally, recovery or retry code should be used only where there is a definite business need.

6.  Containers, but not threads, provide the outermost exception handler for you

Because the requirement to report errors & log stacktraces is so common and basic, most EJB/ web containers & frameworks (Spring, Struts, Swing/ AWT) provide a standard error-handler for you.

These typically return a basic error response & log the exception. Some allow customization, to show a nicer looking error-page.

However, Threads and threaded code (SwingWorker, ExecutorPool etc) do not have nice exception-handlers builtin. Uncaught exceptions thrown in these will typically result in silent failure, which is time-consuming to debug.

For standard web applications & Swing, you can rely on the standard exception-handlers without needing to write any code. If you’re using threads, however, make sure your exceptions will be handled.

7.  Prefer runtime to checked exceptions

Modern Java use and other languages (C#) have moved away from the “checked exception” concept, to strongly prefer runtime (unchecked) exceptions.

Checked exceptions were originally intended for “contingency outcomes” — predictable business results, other than success. The classical example is InsufficientFundsException when attempting to pay or transfer money.

These are useful for specific individual situations, for which an alternate business process & response may exist.

However, they were never conceived to include unpredictable low-level & infrastructure failures — which can occur anywhere in code, at any time, and for which no effective business alternates exist.

“Potential to fail anytime, anywhere” due to underlying causes is simply not meaningful to deal with in a specific way. Runtime exceptions were designed to be unchecked, to allow unpredictable failure to be thrown from anywhere & handled further out. This is much better suited & allows generalized exception handling strategies such as “fail & report”, “retry” or “skip optional step”.

The best approach to dealing with checked exceptions (not representing genuine alternates/ or business contingencies) is to wrap and rethrow using a suitable unchecked exception.

Often, it is most convenient to wrap the entire method body in a catch-block to rethrow checked exceptions.

10 thoughts on “Ten practices for perfect Java Exception handling”

  1. “However, [check exceptions] were never conceived to include unpredictable low-level & infrastructure failures — which can occur anywhere in code, at any time, and for which no effective business alternates exist.”

    That’s a darn interesting statement.
    Out of curiosity, what is your source for that? Who conceived them?
    Reason I wonder is, the JDK itself is horribly cluttered with all these ridiculous checked-exceptions that a client virtually never want to catch — and more keep coming with every new release…
    So if your stmt is correct, it means the people who decide on the JDK have completely misunderstood what checked-exceptions were intended for?

    1. Yes, this was the original intent of checked exceptions — a language mechanism to identify possible contingencies and ensure they were handled.

      This worked great for reporting predictable non-success outcomes back to callers.

      The trouble is that it does not make sense at all for unpredictable low-level failures.. which can effectively happen anywhere, anytime, and are impossible for application code to recover from. Forcing these to be declared is essentially meaningless, since the declarations are needed everywhere.

      This understanding is a synthesis of a range of sources. Barry Ruzek probably expresses this best, but here are a few:

      Barry Ruzek, Oracle: Effective Java Exceptions pg 2
      Smartics: Faults and Contingency Exceptions
      Expert One-on-One J2EE Design and Development: Interview with Rod Johnson

  2. Great effort and a really good site Tom. I’ve been enjoying reading these articles and have learned a lot from them already.

  3. Good explanation tom, i got more detail about catch in java. i will share my friend also those details.but i want more example to given. am waiting your given example and explanation. thanks

  4. Why have AppSqlException, AppFileException and …, Considering there already is SqlException, FileException, …
    Isn’t it better to have a generic AppException?

    About No3 (Keep your exception heirarchy simple) isn’t it best for AppSQLException, AppFileException, …. (and all other internal Exceptions) to be extended from our own AppException?
    This way we can treat AppExceptions and RuntimeExceptions differently. So if an AppException is thrown we can be sure that the Application is still in the right state and keep going but when a RuntimeException is thrown we can consider it fatal and let the Application go down.

    1. AppSqlException and AppConfigException might be better examples — most apps use both SQL and Configuration, for example, but somewhat fewer combine SQL with file management.

      Anyway, the point is that 1) these are runtime exceptions, and 2) they can inherit from a common type.

      Here I’m proposing an application-level FailureException. In the past (as you suggest), I’ve also seen an AppException used — however that design didn’t include the distinction between failures & recoverable exceptions.

      Regarding recovery: your thinking is wrong. In general, we can’t recover. Sometimes we can retry (with added cost & complexity). But our primary goal is to fail cleanly.

      In the very large part, our code should just aim to fail cleanly. We should never assume that a given exception type lets us globally ignore failed business logic, as that means our application will be running in an incorrect state & worse, persist that wrongness to the DB.

      Thanks for your comments, glad you appreciated the article!

  5. Hi Tom,

    I read your post “Checked exceptions: Java’s biggest mistake”. I had a similar post: http://tri-katch.blogspot.com/2016/02/java-checked-exception-is-bad.html.

    I have been thinking about redesigning exception mechanism (not only limited to Java) for 9+ years (http://www.theserverside.com/news/thread.tss?thread_id=43820#225361). And here is the result: http://tri-katch.blogspot.com/2015/05/catch-code-proposal-to-expand-catch-in.html

    Could you take a look and comment?

    Thanks.
    Bo

    1. Hi Bo, thanks for your interest & comments! I’ve looked at your proposal, but it seems to suggest using strings/ fault codes as a kind of replacement for exception subtypes.

      My emphasis is against checked exceptions in general; but specifically, I believe that exception-handling & genuine recovery are relatively rare in code.

      These are the circumstances where a ‘catch by type’ is appropriate and I find the combination of code locality & Java exception types to be sufficient and appropriate for that purpose. So, I don’t support special language support to catch by string/ or fault-code.

      Thanks for your interesting suggestion however!

      Regards,
      Tom

  6. Thanks for your great article that summarizes most of my personal practices from 20+ years of Java development.

    There’s only one statement I’m missing: “An exception is the signal from a method to its caller that it didn’t fulfill its contract.” So, as a caller, if I don’t get an exception, I can safely assume the method did its job, completely. (Of course, the question still has to be answered case-by-case, which special outcomes lie within the contract, thus not being worth an exception.)

    Even though that might seem self-explanatory, there’s lots of mis-understanding among developers on that topic.

Leave a Reply

Your email address will not be published. Required fields are marked *