3.2. Exception Messages

Before we dive into the details of how to properly handle an exception in Java, we first need to better understand how exceptions work and how to interpret error messages produced by the JVM when an exception is not handled properly. Taking a few moments to understand the output from the JVM will allow you to quickly and confidently identify the problem and find a solution.

When an exception occurs, two things happen:

  1. an exception object is created and thrown; and

  2. the normal flow of control is disrupted.

The exception object that is created contains information about the location and cause of the exception.

You have likely encountered the dreaded NullPointerException before reading this tutorial. If you click on the link, you will see the Java API documentation for the NullPointerException class. NullPointerException is a regular Java class that has constructors and methods that can be called from your programs. If you haven’t seen a NullPointerException before, it’s easy to create a program that will generate one.

Test Yourself

Take a moment to carefully read through the program in the box below. In your notes, write what you expect the output to be along with an explanation of what should happen when the program is run. Don’t worry if you are unsure. Write something down and do the best you can.

It may help to look back at what it means for a reference variable to be set to set to null (Example 1 - Refer to No Object).

Code Example
public class Exception {
   public static void main(String[] args) {
      exception();
   } // main

   public static void exception() {
      String s = null;

      if (s.length() > 1) {
         System.out.println("string length > 1");
      } // if
   } // exception
} // Exception

Check your answer by running the code example above on Odin. Below, you will find a video demonstrating how to quickly compile and run this code in an unnamed package. We recommend that you also practice compiling the code to a named package as well by adding a package statement (you choose the name) and the corresponding package directories before compiling. Take a few minutes to review the Named Package section of the Packages chapter if you need a refresher.

When this code is run, the JVM:
  1. Creates a NullPointerException object on the second line of the exception method when it tries to call the length method on a null reference; and

  2. Disrupts the normal flow of control to report to the user that the exception was thrown and abruptly terminates the program.

In the example above, the exception method does not finish executing as it normally would (because of the exception) and the program crashes. Please note that the program doesn’t crash because an exception occurred. Instead, it crashes because the exception was not handled properly.

Here is an annotated version of the output produced by the example code (yours may vary slightly):

A. | Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local0>" is null
B. |     at Exception.exception(Exception.java:9)
C. |     at Exception.main(Exception.java:3)

When you see an error message like this, take a few seconds to read through the message to understand what it is saying. We will break it down line-by-line below:

Line A: The top line in the output always displays the error message contained in the exception object (usually the reason for the exception) along with the exception type (NullPointerException in this case). The exception occurred when the length method was invoked on a null reference. With this information, we can look at our code to figure out that s must have been null since s is the only reference variable on line 9.

The indented lines starting with at in the output are collectively referred to as a stack trace. The stack trace tells the user which methods were active when the program crashed in the order that they were called (from the bottom up). This facilitates faster debugging by allowing you to better understand what was happening in the application when it crashed.

Line B: This is the first line in the stack trace but the second line in the overall output. It indicates the origin of the exception; that is, it provides the class name, method name, filename, and line number where the exception object was first thrown during program execution. Here is a breakdown:

  class name              file name
   ┌───┴───┐           ┌──────┴─────┐
at Exception.exception(Exception.java:9)
             └───┬───┘                │
           method name            line number

Line C. The last line in the stack trace indicates the last executed line of the first method executed by our program; in most cases, this is implicitly the main method since most Java programs start in main. Here is a breakdown:

  class name         file name
   ┌───┴───┐      ┌──────┴─────┐
at Exception.main(Exception.java:3)
             └─┬┘                │
         method name         line number

The stack trace, when read in reverse order (i.e., from bottom to top), tells us a story about what happened when we ran the program.

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local0>" is null
     at Exception.exception(Exception.java:9)
     at Exception.main(Exception.java:3)

In our example, the stack trace tells us that the main method was executed until the program got to line 3, then the exception method (Exception.exception) was called and executed until the program got to line 9, the origin of the exception.

Since the exception method does not handle the exception, the exception object propagated (i.e., thrown/passed back) to its calling method. In general, exception objects will continue to propagate back through the calling methods in the call stack (i.e., the methods we see in the stack trace) until the program either: i) handles the exception object; or ii) lets the exception propagate out of main.

In our example, the exception propagated from exception to main, and since the main method does not handle the exception, the exception continued to propagate out of main and crash the program. Any time an exception is allowed to propagate out of main, the program will crash. It’s our job to make sure that we catch exceptions before they cause a crash. We will see how to do this soon.

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local0>" is null
     at Exception.exception(Exception.java:9)
     at Exception.main(Exception.java:3)

Error messages produced when a program crashes from an exception, like the one shown above, are very informative for us as programmers; however, they are often confusing, startling, or even scary when encountered by end users who just witnessed the program crash and have no way to use the information in the error message. To prevent our users from seeing these error messages, we need to handle exceptions in one of two ways:

  1. avoid them; or

  2. handle them.

In your previous class, you attempted to avoid exceptions. We will focus on properly handling them throughout the rest of this chapter.

Test Yourself

A classmate knows they can’t post their source code to graded assignments on the class Piazza page, so they decide to post the output from an exception they received to see if anyone can help. The output looks like this:

Exception in thread "main" java.lang.ArithmeticException: / by zero
   at TicTacToeGame.calculateScore(TicTacToeGame.java:66)
   at TicTacToeGame.isWinner(TicTacToeGame.java:61)
   at TicTacToeTester.main(TicTacToeTester.java:23)

In your response on Piazza, answer the following questions to help them out:

  1. Where did the exception originate? Mention the filename, method, and line number in your answer.

  2. What type of exception was thrown and what is its FQN?

  3. When the program started running, the main method was called. That method executed until it got to line 23. Continue the story for your classmate:

    1. What happened on line 23 of TicTacToeTester.java?

    2. What happened on line 61 of TicTacToeGame.java?

    3. What happened on line 66 of TicTacToeGame.java?

Test Yourself Solution (Don’t open until completing the question above)

The program started (as all programs do) in the main method. From the output (bottom up), we can tell that the main method is contained within the TicTacToeTester class. The code ran until it got to line 23 of the main method where the isWinner method in the TicTacToeGame class was called. The code continued to line 61 of the isWinner method where it then called the calculateScore method in the TicTacToeGame class. The calculateScore method ran until it got to line 66 where an ArithmeticException was created due to the program dividing by zero.

Since the program crashed, we know the programmer did not properly avoid or handle the exception. They should start by looking at line 66 in TicTacToeGame.java to try and find the bug.

It is also worth mentioning that, in Java, methods can either return a value OR throw (propagate) an exception. In this case, the exception originated in the calculateScore method. Since it was not handled, it was automatically propagated to the isWinner method and then the main method. The exception wasn’t handled in any of these methods, so the program ultimately crashed.

Rapid Fire Review
  1. What is an exception in Java?

    1. A syntax error that occurs during compilation.

    2. An event that occurs during the execution of a program that encounters an error or exceptional situation.

    3. A type of loop in Java.

    4. A command used to compile Java code.

  2. When do exceptions occur in a Java program?

    1. During compilation.

    2. At runtime.

    3. During linking.

    4. When the program is being edited.

  3. What happens when an exception occurs in a Java program?

    1. The program continues running normally.

    2. The program automatically fixes the error.

    3. An exception object is thrown, and the normal flow of control is disrupted.

    4. The program pauses and waits for user input.

  4. What is a NullPointerException?

    1. An error caused by trying to access an element outside the bounds of an array.

    2. An exception thrown when an application tries to use a null object reference.

    3. An error that occurs during the compilation of a program.

    4. A method that prints the length of a string.

  5. What information does the top line of an exception message provide?

    1. The total runtime of the program.

    2. The type of exception and a brief description of what caused it.

    3. The current value of all variables.

    4. The location of the syntax error in the code.