3.4. Handling Exceptions (Try-Catch)

We will continue with the same code example from the last section:

Original 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

To handle the exception in the example above, you need to make use of a special control flow syntax known as a try block or try-catch block. With this syntax, you place code that can throw an exception into the try block, then place code for how you want to deal with the exception in the catch block. These two go together, which is why we often refer to it as a try-catch block. During execution, the try-catch block works as follows:

Try-Catch Semantics

  1. Each line in the try block is executed until an exception object is thrown. If an exception is not thrown, the try block completes normally and the code in the catch block(s) is not executed.

  2. If an exception is thrown from within the try block, the JVM redirects the flow of control into the appropriate matching catch block. In other words, the code in the try block stops executing and the program jumps to the catch block associated with the type of exception that occurred.

    Note

    A try block can have multiple associated catch blocks. The only catch block that will execute is the one that is associated with the type of exception that is thrown.

  3. After the catch block is executed, the flow of control is redirected immediately after the entire try-catch construct.

Here is an example (Notice that we specify NullPointerException in the catch block:

try {
   if (s.length() > 1) {
      // Prints only when s != null
      System.out.println("string length > 1");
   } // if
} catch (NullPointerException npe) {
   // Prints only when s == null
   System.out.println("a NullPointerException was thrown!");
} // try

// Always prints
System.out.println("I will print regardless of the value of s.");

This try-catch block differentiates itself from the previous examples in two ways:

  1. we did not perform any condition checking for the exceptional situation–in this case, we did not compare the value of s to null; and

  2. the exception is still reported, however, it’s done so using code that we wrote (and, therefore, can customize) and using code that does not necessarily cause the program to abruptly terminate.

Here is a video with a larger code example demonstrating the benefits of handling exceptions instead of trying to avoid them:

https://www.youtube.com/watch?v=TETdh48t4YM

IMAGE ALT TEXT

Learn by Experimenting!

Using the try-catch semantics as a guide, try to predict the output from each of the programs below. Then, quickly test your answers by compiling/running the programs on Odin.

  1. What is the full the output of the following program?

    public class DivisionExample {
       public static void main(String[] args) {
          int a = 10;
          int b = 2;
    
          try {
             int result = a / b;
             System.out.println("Result: " + result);
          } catch (ArithmeticException e) {
             System.out.println("Cannot divide by zero!");
          } // try
       } // main
    } // DivisionExample
    
  2. What would be the output of the program above if we changed variable b to have a value of 0 instead of 2?

  3. What is the full output of the following program?

    public class MultipleCatchExample {
       public static void main(String[] args) {
          try {
             int[] array = {1, 2, 3};   // 1
             int a = 10, b = 0;         // 2
             String str = null;         // 3
    
             int result = a / b;
    
             System.out.println("Array element: " + array[5]);
             System.out.println("String length: " + str.length());
    
          } catch (ArithmeticException ae) {
             System.out.println("Cannot divide by zero.");
          } catch (ArrayIndexOutOfBoundsException aioobe) {
             System.out.println("Invalid array index.");
          } catch (NullPointerException e) {
             System.out.println("Cannot call a method on a null reference.");
          } // try
    
          System.out.println("Got to the end!");
       } // main
    } // MultipleCatchExample
    
  4. Change the values assigned to the variables declared on the lines marked 1, 2, and 3 so that no exceptions are thrown and the program only prints output from the two print statements in the try block along with “Got to the end!” from the final print statement.

  5. Is it possible to make the program print both “Invalid array index.” and “Cannot divide by zero.” only by changing the values assigned in the lines marked 1, 2, and 3? If so, how would you do it? If not, explain why not.

Remember to check your answers by running the code on Odin. We encourage you to explore other questions that may arise while working through these. As always, post any questions you have on the course Piazza page. Posting questions/answers to questions found in the reading is encouraged!