Before you begin

This unit is part of the “Intro to Java programming” learning path. Although the concepts discussed in the individual units are standalone in nature, the hands-on component builds as you progress through the units, and I recommend that you review the prerequisites, setup, and unit details before proceeding.

Unit objectives

  • Learn exception-handling basics
  • Understand the exception hierarchy and how to use multiple catch blocks

Exception-handling basics

No program ever works 100 percent of the time, and the designers of the Java language knew this. The Java platform has built-in mechanisms for handling situations in which your code doesn’t work exactly as planned.

An exception is an event that occurs during program execution that disrupts the normal flow of the program’s instructions. Exception handling is an essential technique of Java programming. You wrap your code in a try block (which means “try this and let me know if it causes an exception”) and use it to catch various types of exceptions.

To get started with exception handling, take a look at the code in Listing 1.

Listing 1. Do you see the error?

@Test
public void yetAnotherTest() {
  Logger l = Logger.getLogger(Employee.class.getName());
//    Employee employee1 = new Employee();
  Employee employee1 = null;
  employee1.setName("J Smith");
  Employee employee2 = new Employee();
  employee2.setName("J Smith");
  l.info("Q: employee1 == employee2?      A: " + (employee1 == employee2));
  l.info("Q: employee1.equals(employee2)? A: " + employee1.equals(employee2));
}

Notice that the Employee reference is set to null. Run this code and you get the following output:


java.lang.NullPointerException
  at com.makotojava.intro.EmployeeTest.yetAnotherTest(EmployeeTest.java:49)
  .
  .
  .

This output is telling you that you’re trying to reference an object through a null reference (pointer), which is a pretty serious development error. (You probably noticed that Eclipse warns you of the potential error with the message: Null pointer access: The variable employee1 can only be null at this location. Eclipse warns you about many potential development mistakes — yet another advantage of using an IDE for Java development.)

Fortunately, you can use try and catch blocks (along with a little help from finally) to catch the error.

Using try, catch, and finally

Listing 2 shows the buggy code from Listing 1 cleaned up with the standard code blocks for exception handling: try, catch, and finally.

Listing 2. Catching an exception

@Test
public void yetAnotherTest() {
  Logger l = Logger.getLogger(Employee.class.getName());

  //    Employee employee1 = new Employee();
  try {
    Employee employee1 = null;
    employee1.setName("J Smith");
    Employee employee2 = new Employee();
    employee2.setName("J Smith");
    l.info("Q: employee1 == employee2?      A: " + (employee1 == employee2));
    l.info("Q: employee1.equals(employee2)? A: " + employee1.equals(employee2));
  } catch (Exception e) {
    l.severe("Caught exception: " + e.getMessage());
  } finally {
    // Always executes
  }
}

Together, the try, catch, and finally blocks form a net for catching exceptions. First, the try statement wraps code that might throw an exception. In that case, execution drops immediately to the catch block, or exception handler. When all the trying and catching is done, execution continues to the finally block, whether or not an exception occurred. When you catch an exception, you can try to recover gracefully from it, or you can exit the program (or method).

In Listing 2, the program recovers from the error and then prints out the exception’s message:


Sep 19, 2015 2:01:22 PM com.makotojava.intro.EmployeeTest yetAnotherTest
SEVERE: Caught exception: null

The exception hierarchy

The Java language incorporates an entire exception hierarchy consisting of many types of exceptions grouped into two major categories:

  • Checked exceptions are checked by the compiler (meaning the compiler makes sure that they get handled somewhere in your code). In general, these are direct subclasses of java.lang.Exception.
  • Unchecked exceptions (also called runtime exceptions) are not checked by the compiler. These are subclasses of java.lang.RuntimeException.

When a program causes an exception, you say that it throws the exception. A checked exception is declared to the compiler by any method with the throws keyword in its method signature. Next is a comma-separated list of exceptions that the method could potentially throw during its execution. If your code calls a method that specifies that it throws one or more types of exceptions, you must handle it somehow, or add a throws to your method signature to pass that exception type along.

When an exception occurs, the Java runtime searches for an exception handler somewhere up the stack. If it doesn’t find one by the time it reaches the top of the stack, it halts the program abruptly, as you saw in Listing 1.

Multiple catch blocks

You can have multiple catch blocks, but they must be structured in a particular way. If any exceptions are subclasses of other exceptions, the child classes are placed ahead of the parent classes in the order of the catch blocks. Listing 3 shows an example of different exception types structured in their correct hierarchical sequence.

Listing 3. Exception hierarchy example

@Test
public void exceptionTest() {
  Logger l = Logger.getLogger(Employee.class.getName());
  File file = new File("file.txt");
  BufferedReader bufferedReader = null;
  try {
    bufferedReader = new BufferedReader(new FileReader(file));
    String line = bufferedReader.readLine();
    while (line != null) {
      // Read the file
    }
  } catch (FileNotFoundException e) {
    l.severe(e.getMessage());
  } catch (IOException e) {
    l.severe(e.getMessage());
  } catch (Exception e) {
    l.severe(e.getMessage());
  } finally {
    // Close the reader
  }
}

In this example, the FileNotFoundException is a child class of IOException, so it must be placed ahead of the IOException catch block. And IOException is a child class of Exception, so it must be placed ahead of the Exception catch block.

try-with-resources blocks

The code in Listing 3 must declare a variable to hold the bufferedReader reference, and then in the finally must close the BufferedReader.

Alternative, more-compact syntax (available as of JDK 7) automatically closes resources when the try block goes out of scope. Listing 4 shows this newer syntax.

Listing 4. Resource-management syntax

@Test
public void exceptionTestTryWithResources() {
  Logger l = Logger.getLogger(Employee.class.getName());
  File file = new File("file.txt");
    try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
      String line = bufferedReader.readLine();
      while (line != null) {
// Read the file
      }
    } catch (Exception e) {
      l.severe(e.getMessage());
    }
}

Essentially, you assign resource variables after try inside parentheses, and when the try block goes out of scope, those resources are automatically closed. The resources must implement the java.lang.AutoCloseable interface; if you try to use this syntax on a resource class that doesn’t, Eclipse warns you.

Test your understanding

  1. Which of these statements is true regarding exceptions?

    1. An exception is an abnormal flow of execution in a Java program.
    2. A checked exception is not checked by the compiler, so you must check for the exception yourself.
    3. You must specify all runtime exceptions on your method signature by using the throws keyword.
    4. None of the above.
    5. All of the above.
  2. The finally block executes every time, whether or not an exception was thrown.

    1. True
    2. False
  3. Will the following code compile? Explain your answer.

    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.logging.Logger;
    
    public class Test1 {
       
       private static final Logger l = Logger.getLogger(Test1.class.getName());
       
       public void hierarchyExample() {
          File file = new File("file.txt");
          
          BufferedReader bufferedReader = null;
          
          try {
             bufferedReader = new BufferedReader(new FileReader(file));
             String line = bufferedReader.readLine();
             while (line != null) {
                // Read the line
             }
          } catch (IOException e) {
             l.severe(e.getMessage());
          } catch (FileNotFoundException e) {
    
             l.severe(e.getMessage());
          } catch (Exception e) {
             l.severe(e.getMessage());
          }
       }
    
    }
    

  4. A class used in a try-with-resources block must implement which of these interfaces?

    1. java.lang.Iterable
    2. java.lang.AutoClosable
    3. Both java.lang.Iterable and java.io.Closable
    4. Both java.lang.AutoCloseable and java.lang.Exception
    5. None of the above.
  5. An unchecked exception does not have to be specified to the compiler, and may be thrown at runtime.

    1. True
    2. False
  6. Which of these Exception subclasses are unchecked exceptions? Use the resources in the “For further exploration” section, along with the JDK Javadoc, for help with your answer.

    1. java.lang.IllegalArgumentExeption
    2. java.sql.SQLException
    3. java.time.DateTimeException
    4. java.lang.IllegalArgumentException
    5. All of the above.
  7. What special considerations must you use if a checked exception is thrown during the execution of a method you’ve written?

    1. Ensure that the exception is declared using the throws keyword in your method’s signature, or catch and handle the exception in your method.
    2. None. Checked exceptions are only checked by the runtime, not the compiler.
    3. Be sure to use a finally block in all affected code.
    4. There’s no such thing as a checked exception.
    5. None of the above.
  8. What tells the compiler that an exception is an unchecked exception?

    1. There’s no way for the compiler to know if an exception is unchecked, which makes exceptions such a difficult topic in Java.
    2. An unchecked exception is a direct subclass of java.lang.Exception.
    3. There’s no such thing as an unchecked exception.
    4. The compiler does not check for unchecked exceptions.
    5. None of the above.

Check your answers

  1. Which of these statements is true regarding exceptions?

    1. An exception is an abnormal flow of execution in a Java program.
    2. A checked exception is not checked by the compiler, so you must check for the exception yourself.
    3. You must specify all runtime exceptions on your method signature by using the throws keyword.
    4. None of the above.
    5. All of the above.
  2. The finally block executes every time, whether or not an exception was thrown.

    1. True
    2. False
  3. Will the following code compile? Explain your answer.

    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.logging.Logger;
    
    public class Test1 {
       
       private static final Logger l = Logger.getLogger(Test1.class.getName());
       
       public void hierarchyExample() {
          File file = new File("file.txt");
          
          BufferedReader bufferedReader = null;
          
          try {
             bufferedReader = new BufferedReader(new FileReader(file));
             String line = bufferedReader.readLine();
             while (line != null) {
                // Read the line
             }
          } catch (IOException e) {
             l.severe(e.getMessage());
          } catch (FileNotFoundException e) {
    
             l.severe(e.getMessage());
          } catch (Exception e) {
             l.severe(e.getMessage());
          }
       }
    
    }
    

    Answer: No. The code will not compile because the catch block for FileNotFoundException should be before the catch block for IOException, because FileNotFoundException is a subclass of IOException. Instead it is listed after, and the code will not compile.

  4. A class used in a try-with-resources block must implement which of these interfaces?

    1. java.lang.Iterable
    2. java.lang.AutoClosable
    3. Both java.lang.Iterable and java.io.Closable
    4. Both java.lang.AutoCloseable and java.lang.Exception
    5. None of the above.
  5. An unchecked exception does not have to be specified to the compiler, and may be thrown at runtime.

    1. True
    2. False
  6. Which of these Exception subclasses are unchecked exceptions? Use the resources in the “For further exploration” section, along with the JDK Javadoc, for help with your answer.

    1. java.lang.IllegalArgumentExeption
    2. java.sql.SQLException
    3. java.time.DateTimeException
    4. java.lang.IllegalArgumentException
    5. All of the above.
  7. What special considerations must you use if a checked exception is thrown during the execution of a method you’ve written?

    1. Ensure that the exception is declared using the throws keyword in your method’s signature, or catch and handle the exception in your method.
    2. None. Checked exceptions are only checked by the runtime, not the compiler.
    3. Be sure to use a finally block in all affected code.
    4. There’s no such thing as a checked exception.
    5. None of the above.
  8. What tells the compiler that an exception is an unchecked exception?

    1. There’s no way for the compiler to know if an exception is unchecked, which makes exceptions such a difficult topic in Java.
    2. An unchecked exception is a direct subclass of java.lang.Exception.
    3. There’s no such thing as an unchecked exception.
    4. The compiler does not check for unchecked exceptions.
    5. None of the above.

    Previous: Next steps with objectsNext: Building Java applications