Java has checked exceptions and is out on a limb. Is there a reason, why other languages like C++, Objective-C, C#, Scala, Xtend don’t support this concept? What is the problem about checked exceptions and what can we do instead? And most important: What do water wings and checked exceptions have in common? This article gives the answer to all of these questions and shows why unchecked exceptions are the better choice.

The Root of all Evil: Enforced Handling

Consider the following snippet:

This code doesn’t compile, since Files.readAllBytes() throws a checked exception. We are forced to handle this IOException. That’s annoying, but what can we do?

  • Option A) Rethrow the exception
  • Option B) Handle the exception

Option A) Rethrow the Exception

This makes the compiler happy. But are we happy now? Actually no, since we can easily run into troubles with rethrowing.

Checked Exceptions are Part of the Signature

Consider the following method call stack.

Cascading Signature Changes

If we throw an IOException in UserRepository.getContent(Path) and want to handle them in ContextMenu.menuClicked(), we have to change all method signatures up to this point. What happens, if we later want to add a new exception, change the exception or remove them completely? Yes, we have to change all signatures. Hence, all clients using our methods will break. Moreover, if you use an interface of a library (e.g. Action.execute()) you are not able to change the signature at all.

Exposing Implementation Details in the Signature

Consider the method signature from the above example:

Assume that UserRepository is an interface. Will the various implementations of UserRepository throw an IOException like our file system based implementation? Not at all. A database implementation might throw a SqlException or a WebService might throw a TimeoutException. The point is that the type of exceptions (and whether they are thrown at all) is specific to the implementation.

But the client is forced to handle the IOException although he knows that this exception will not occur in the database implementation he uses. Moreover, the client doesn’t care if an IOException or a SqlException is thrown. He just wants to know, if something went wrong. Consequently the thrown exception should be implementation agnostic.

Option B) Handle the Exception

Ok, let’s handle the exception! We’re going to handle the exception – by… well… how?

No Appropriate Handling Possible at this Point

That’s the point! What to do with the IOException in this low-level method? We can’t appropriately handle them here. Maybe it could be handled at a higher level by giving the user a feedback in the UI, but that’s nothing we should do within this method. Nevertheless, the compiler enforces us to handle it here.

No Healing Possible at all

A common “handling” of a checked exception is to log the error and to abort (the current operation or the whole application if we can’t continue). Log and Exit. That’s ok. But why we don’t let the exception fly through the whole stack trace, which would have the same effect? If we can’t heal us from this exception, why are we forced to handle them? The enforced handling makes no sense at all if we want to exit the operation anyway in case of an exception.

Further Issues

Checked exceptions leads to annoying boilerplate code (try {} catch () {}). Every time you call a method that throws a checked exception, you have to write the try-catch-statement.

The compiler forces us to catch the exception. Often this ends up in a mixing of main logic and error handling. But these are separate concerns that should be handled separately and in a coherent way. The multiple try-catch-statements let your error handling scatter over your whole code base.

There is the danger that we simply forget to implement the catch block, because we didn’t really know what to do or assume that this exception will never occur. Or we just want to quickly test a method call throwing an exception and plan to implement the catch block later, but forget it. An empty catch block swallows the exception. We will never be informed when the exception occurs. The application will behave incorrectly and we have no clue why. Happy debugging.

And finally, a lot of checked exceptions are technical (like IOException) and don’t provide us with semantics regarding to the domain.

The Solution: Use Unchecked Exceptions And Wrap Checked Exceptions

If you define your own exception, always use unchecked exceptions (RuntimeException). If you have to handle a checked exception, wrap them in your own domain/high-level exception and rethrow them. In our getContent() method we can throw our own RepositoryException that extends RuntimeException.

Now the client of getContent() (or getUsers()) has the freedom to handle the RepositoryException at the point where it is most appropriate. The client decides, not the compiler.  He can let the exception fly up to a central point where all exceptions are handled and, for instance, provide feedback to the user.

Is there a healing for the RepositoryException? Fine, then do it. If not, no problem, either you catch it and provide a feedback to the user or you don’t catch and exit the operation this way.

It’s true, that this approach demand more discipline. You should not forget to catch the RepositoryException if you want to handle them. Moreover, you have to document that your method throws a RepositoryException. The compiler doesn’t take you by the hand any longer. You have to take care about the exception handling. But you are much more flexible and relieved from the boilerplate code.

Documentation of Unchecked Exceptions

But how do I know, that a method throws an unchecked exception? The compiler doesn’t tell me. Yes, you are responsible to document unchecked exceptions carefully. There are two options:

a) Use JavaDoc

b) Use the throws clause

Some people state that JavaDoc should be used for unchecked exceptions and the throws clause only for checked exceptions. However, I don’t agree with this dogmatic approach. I’m more pragmatic in this point: I personally always use the throws clause, simply because you get better tooling support depending on your IDE (e.g. code completion when writing the exception in the catch block, highlighting of the throwing method if you select the exception in the catch block or vice versa). Moreover, you can still use JavaDoc additionally for further documentation about the exception.

Summary

Use unchecked exceptions. They enable freedom and flexibility. We decide on our own, whether and where we want to handle exceptions. Not the compiler. But this advantage demands more responsibility.

“With great power comes great responsibility”

There is still one question left. What do water wings and checked exceptions have in common?

At the beginning you feel safer with them, but later they prevent you from swimming quickly.

Video Version of this Blog Post

The guys from Webucator have created a nice video out of this blog post. Enjoy it!

  1. Ezequiel Block says:

    Hi Philipp,

    Checked exceptions have a purpose, they are expected conditions that may arise. Contrary to unchecked exceptions that are unexpected things that may occur, like and OOM, errors in filesystem, etc.

    Consider the following method:

    public void extractMoneyFromAccount(String acctNumber, BigDecimal amount) throws NoFundsException

    In this case, programatically, as a creator of this service, you want to let know to your api clients that this condition is to be “expected”, so this is the way to “force” them to handle it in code. This is not the same as any unexpected condition that may arise, whether is a coding error (NPE), Java internal Errors, OutOfBoundExceptions, etc.

    Checked exceptions force you to handle the situation. What should i do in this situation? should I offer the user another account to extract money from? should I do … x thing?

    In the unchecked world, in most cases, you have nothing to do, let it scale to (nothing to do as there are no inforcement to handle them) whatever you have as the last exception handler, log it, present a generic error message, etc.

    Ask yourseft the following: what´s the difference between a NullPointerException and IOException? IOException can be expected (filesystem full, no permissions, etc.), and as a programmer can react to it (not always) whereas a NullPointerException is not expected at all.

    Best Regards
    Ezequiel.

    • Philipp Hauer
      Philipp Hauer says:

      Hi Ezequiel,
      Thanks for sharing your point of view! At the end it’s a subjective and sometimes emotional topic. Essentially, it comes down to the question how you consider the enforced handling. If you appreciate the safety (because you can’t forget to handle an exception), than checked exceptions are your friends. But if flexibility and freedom is more important for you, you have to go with unchecked exceptions. It’s basically this trade-off, everybody has to make on their own.

      But I don’t agree with the rule “Checked Exception if you can do something, unchecked if you can do nothing”. Why shouldn’t I use unchecked exception for situation where the client/developer can handle them, but I don’t want force him to? He can device whether he wants to handle it and he can device at which point he wants to handle it. He devices, not me. The developer knows best if this is an exception he wants or can handle, not me as the API designer. But you are right: this freedom means that the developer has to take care, which can be more dangerous sometimes.

      Cheers
      Philipp

  2. Jukka Nikki says:

    Thanks for good article Philipp.

    For some situations “extractMoneyFromAccount(..) throws NoFundsException” might be just ok, but it’s not very well compatible to streams and potentially adds lot of boilerplate code.

    My problem currently are DTO’s which throw checked exceptions. Those DTO’s are really blockers for Streams, and require high amount of try / catch constructions. Here’s example how to get rid of such legacy constructions or minimize pain they create.

    Consider DTO with method

    public class ExceptionalDto {
    public String getString () throws IOException {
    return “value”;
    }
    }

    And now, how to get value easily? Here’s what I want ..

    ExceptionalDto dto = new ExceptionalDto();
    System.out.println(extract(dto::getString));

    For this I have created simple method, which can be used from statically imported utility class

    public static R extract(ThrowingSupplier extractionRule) {
    return extractionRule.get();
    }

    In addition to this I need ThrowingSupplier

    @FunctionalInterface
    public interface ThrowingSupplier extends Supplier {

    @Override
    default R get(){
    try{
    return getThrows();
    }catch (Exception e){
    throw new RuntimeException(e); // Here could be also our own ExtractionException if needed
    }
    }

    R getThrows() throws Exception;
    }

    And viola — annoying checked exceptions are away.

    Source of idea, as credits need to go to right address: http://codingjunkie.net/functional-iterface-exceptions/

    Cheers
    Jukka

Leave a Reply

Your email address will not be published.