What Every Java Developer Should Know About Checked and Unchecked Exceptions

adminguy's picture
Posted March 4th, 2015 by adminguy



Java uses Exceptions -- unlike error codes in C -- to signify problems while code is executing. Java Exceptions, like most things in the world, come in a multitude of shapes and sizes. Try looking at the tree of subclasses of java.lang.Exception, and you'll know exactly what I mean. The diversity is not just in the fact that there are so many Exception classes; the semantics also differ. But fortunately there are only two differing families when it comes to semantics of Java Exceptions: Checked Exceptions and Unchecked Exceptions. They are represented within Java as subclasses of java.lang.Exception and java.lang.RuntimeException respectively.

We will understand what both these type of exceptions mean with code samples below.
Checked Exceptions
Take a look at this simple code snippet shown below:
Reader reader = null;
try {
    reader = new FileReader("weather_data.txt" );           
} catch(FileNotFoundException fnfe) {
    // do something
} finally {
    // close the reader
Code Example 1
If you check the Javadocs of FileReader's constructor, you will notice that it declares FileNotFoundException. And if you examine the class hierarchy of FileNotFoundException, you will find it to be a descendant of java.lang.Exception. FileNotFoundException is a Checked Exception and must be handled in the code where it is likely to be thrown. If you'd like to understand what "it needs to be handled in code"  means in a hands-on way, try removing the catch block from Code Example 1. You will notice that the code does not even compile. That's because FileNotFoundException is a Checked Exception and must be handled. It must be noted that using a catch block is just one way of handling an Exception, there's another way too, but let's not get into details that will sidetrack the main topic. The important concept to understand here is that a Checked Exception cannot be ignored in code; it has to be handled.
A natural question you might have at this point is: what's so special about Checked Exceptions that the language forces us to handle then? Why can't we ignore them? It's because a Checked Exception represents a problem -- which the programmer could not have controlled -- that can occur when the code is executing. It is only natural to expect that such a potential problem should be handled, because in the event that it is not, the code may fail in a totally unrelated place, making the software difficult to use for the user and difficult to debug for the developer. Forcing exceptions to be handled, ensures the programmer thinks about them and they are dealt with, as close as possible, to the point of failure. 
Many things could have gone wrong in the code shown in Code Example 1: the file may not exist at all, it may exist but could get deleted just before the FileReader is created, or it may exist on a mounted network drive which becomes inaccessible due to network failure. All of these are valid causes of failure and cannot be ignored. That's why FileNotFoundException is a Checked Exception, forcing the programmer to think about all that could go wrong when the code is executing, and deal with it gracefully. 
Unchecked Exceptions
In the previous section we understood the rationale for Checked Exceptions. In this section we will examine Unchecked Exceptions, once again with an example. Most programmers are familiar with ArrayIndexOutOfBoundsException which is thrown when we try to read an array beyond its current size - as shown in the code sample below. 
int numbers[] = new int[] {0,1,2,3,4,5,6,7,8,9};
System. out.println("The eleventh number is - " + numbers[10]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException : 10
       at Widget.main( Widget.java:30)
Code Example 2

If you look at the hierarchy of ArrayIndexOutOfBoundsException, you will notice it is a subclass of java.lang.RuntimeException. You will also notice that the code in Code Example 2 compiles just fine even though it is not wrapped inside a try...catch block. ArrayIndexOutOfBoundsException is an Unchecked Exception because it is a subclass of   java.lang.RuntimeException and that's the reason why we got away without wrapping the code in a try...catch block. It is legal to ignore Unchecked Exceptions.
Just saying it's legal to ignore Unchecked Exceptions doesn't really cut it. The curious mind is going to need further explanations. Why is it legal to ignore them? What's so different about certain Exceptions, that the Java team decided to show leniency and make them unchecked? Why is it acceptable to ignore them? If you look carefully at the code in Code Example 2, you will notice that a diligent programmer could have prevented the exception from occurring by checking the size of the array before attempting to reference a certain element. In such a case if an exception does occur - as it did in Code Example 2 - it is purely because the developer who wrote it did not practice defensive coding. 

it does not make sense to force a programmer to handle Unchecked Exceptions, since they are usually thrown due to programmer negligence. Handling a RuntimeException is like saying:

    Look I am going to write some sloppy code here, but I will recover from my sloppiness by catching this Exception.

Noooo that's not done! You don't write sloppy code and recover from it by catching Exceptions. But like all rules, this one also has some gray area which gives rise to potential exceptions (pardon the pun). There's at least one instance, as shown below, where I have often seen a RuntimeException being handled. 
try {
    String numAsString = "1.2";
    Double. parseDouble(numAsString);
} catch(NumberFormatException nfe) {
    // handle it
Code Example 3
Even though NumberFormatException is an Unchecked Exception, it is often handled because there isn't a super easy way to check if the String variable numAsString represents a valid Double. Catching the Exception and handling an error situation in the catch block is often the simplest way of handling it.
In summary, Unchecked Exceptions need not be handled in code, because they usually denote programmer oversight and Unchecked Exceptions are descendants of java.lang.RuntimeException. Checked Exceptions on the other hand, do need to be handled in code, because they denote things beyond the developers control that could go wrong while the code is executing. Checked Exceptions are descendants of java.lang.Exception and never java.lang.RuntimeException. I had to make the second distinction because java.lang.RuntimeException is also a subclass of java.lang.Exception
I hope this article helped you understand the difference between Checked and Unchecked Exceptions from a coding and a philosophical perspective. But before we end, I'd like to leave you with some food for thought. Do we really need Checked Exceptions? I don't think there's an easy answer; there are intelligent people on both sides of the debate, so I'll let you decide.