Checked and Unchecked Exceptions in Java

Java has two types of exceptions – checked and unchecked. In short – checked are meant for cases when the developer can reasonably recover from the exception, while unchecked exceptions are programming errors that can’t be dealt with. This article explains when to use which.

But it is not that simple – checked exceptions are making the code “uglier”. They force the developer to write try/catch blocks or to rethrow the exception. But rethrowing hides another problem – some exceptions should not cross module boundaries. The most common thing to do when you are forced to catch a checked exception, which you have no idea what to do with, is to simply wrap it in a RuntimeException and rethrow it.

Actually, it might not be the most common – especially novice programmers tend to swallow exceptions, with empty catch blocks. Log & rethrow leads to doubled stacktraces sometimes, if there is some general layer for exception handling. Anyway, there are multiple bad practices here that lead to code that’s hard to debug and maintain.

Some say checked exceptions should be eliminated completely, given the verbosity, tediousness and error-proneness they introduce. C# does not have checked exceptions at all. Of course eliminating them should take into account backward compatibility.

I, however, believe the decision to have these two types of exceptions has its plus(es). It forces the developer to think that an exception is likely to happen in this situation, so he must take measures. The API declares that it will throw exceptions and the developer sees this compile-time. It enforces compile-time safety. You should not wait until the code goes to production to discover that something might fail. Javadoc? Well, a good option to say that, but I bet no one will read the javadoc until the exception actually happens.

So, how to have the “best of both worlds” ? I had a bizarre idea (explained in details here) for APIs to define two interfaces (linked through inheritance, so that only one interface is actually supported), and providing a way, through a factory, to get either an implementation whose methods throw checked exceptions, or one that wraps the checked exceptions into unchecked ones. It may be viable, it may be stupid, I can’t tell. For now it just looks strange.

But the above is a workaround at best. Then another idea came – introduce @RethrowExceptions annotation on methods. It will tell the compiler that in this method you don’t want to handle checked exceptions, but you also don’t want to declare them to be thrown. (The name of the annotation can be improved). In the simplest implementation that comes to my mind this can simply tell the compiler to surround the whole method body with try {..} catch (Exception ex) { throw new RuntimeException(ex);}. The benefits:

  • you are still warned by the compiler that the method you are using can throw an exception and you must think of handling it
  • you don’t make your code ugly by needless try/catches. And you don’t force your callers to think what to do with the exception
  • the possibility of swallowing the exception is decreased.

So in short – such an annotation would mark a method as one that is unable to handle the exception and does not want to propagate this decision to its callers.

This idea sounds less bizarre. I guess it can be implemented even now, using a compiler plug-in. Or perhaps it is already implemented in something like project lombok?

13 thoughts on “Checked and Unchecked Exceptions in Java”

  1. I see. Your “throws” syntax has the same idea as my annotation. Perhaps they didn’t like the syntactical changes. Or perhaps they’re Oracle 🙂

  2. For your @RethrowExceptions idea: the JVM doesn’t have the concept of a checked vs unchecked exception, so @RethrowExceptions wouldn’t even need to wrap the exception. It could just pretend it’s unchecked at that method.

    In fact, you can even throw a checked exception in an unchecked manner!

    1 public class Unchecked {
    2
    3 @SuppressWarnings(“unchecked”)
    4 public static void uncheckedThrow(Exception exception) {
    5 Unchecked asUnchecked = new Unchecked();
    6 Unchecked raw = asUnchecked;
    7 raw.t = exception;
    8 asUnchecked.throwIt();
    9 }
    10
    11 private T t;
    12
    13 public void throwIt() throws T {
    14 throw t;
    15 }
    16
    17 public static void main(String[] args) {
    18 Exception checked = new Exception();
    19 uncheckedThrow(checked);
    20 }
    21 }

  3. Here is a very simple solution to your Checked/Unchecked dilemma.

    Think of a Unchecked Exception as a testable condition before code executes.
    for example…
    x.doSomething(); // the code throws a NullPointerException
    …the code should possibly have had the following…
    if (x==null)
    {
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
    }
    x.doSomething();

    Think of a Checked Exception as an un-testable condition that may occur while the code executes.

    Socket s = new Socket(“google.com”, 80);
    InputStream in = s.getInputStream();
    OutputStream out = s.getOutputStream();

    …in the example above, the URL (google.com) may be unavailable to due the DNS server being down. Even at the instant the DNS server was working and resolved the ‘google.com’ name to an IP address, if the connection is made to google.com, at anytime afterword, the network could go down. You simply can not test the network all the time before reading and writing to streams.

    There are times where the code simply must execute before we can know if there is a problem. By forcing developers to write their code in such a way to force them to handle these situations, I have to tip my hat to the creator of Java that invented this concept.

    In general, almost all the APIs in Java follow the 2 rules above. If you try to write to a file, the disk could fill up before completing the write. It is possible that other processes had caused the disk to become full. There is simply no way to test for this situation. For those who interact with hardware where at any time, using the hardware can fail, I believe Checked Exceptions are the best solution for the language.

    Things get interesting when dealing with language interpreters. According to the rules above, should a Syntax Error be considered a Checked or Unchecked Exception? I would argue that if the syntax of the language can be tested before it gets executed, it should be an UncheckedException. If the language can not be tested — similar to how assembly code runs on a personal computer, then the Syntax Error should be a Checked Exception.

    There is a gray area to this. In the event that many tests are needed (a mind blowing if statement with lots of && and ||), the exception thrown will be a CheckedException simply because it’s too much of a pain to get right — you simply can’t say this problem is a programming error. If there are much less than 10 tests (e.g. ‘if (x == null)’), then the programmer error should be a UncheckedException.

    The 2 rules above will probably remove 90% of your concern over which to choose from. To summarize the rules, follow this pattern…
    1) if the code to be execute can be tested before it’s executed for it to run correctly, if an Exception occurs — a.k.a. a programmer error, the Exception should be an UncheckedException (a subclass of RuntimeException).
    2) if the code to be executed can not be tested before it’s executed for it to run correctly, the Exception should be a Checked Exception.

  4. @Andy – it was there before my post, I just wasn’t aware of it before writing it, and only saw it’s implemented after right after I wrote it. So the last sentence has a link to SneakyThrows

Leave a Reply

Your email address will not be published.