Handling Exceptions

The term exception means "exceptional condition" and is an occurence that alters the normal program flow. A bunch of things can lead to exceptions, including hardware failures, resource exhaustion and good old bugs. When an exceptional event occurs in Java, an exception is said to be thrown. The code that handles the exception is called the exception handler and it catches the thrown exception. Exception handling works by transferring the execution of a program to an appropriate exeception handler which knows how to deal with the exception.

Exception handling should be used

Advantages of error-handling are

Differentiate among checked, unchecked exceptions, and errors

All exception classes are subtypes of class Exception, this class derives from the class throwable. The figure below shows the exception hierarchy for the eception class.

As seen above there are two subclasses that derive from Throwable, Exception and Error.

Error Class represents unusual situations that are not caused by program errors or anything that would normally happen during program execution, such as JVM running out of memory. Generally your program won't be able to recover from this type of Error, so you're not required to handle them. The compiler will not complain if you do not catch these types of errors. Technically Errors are not exceptions as they do not derive from the Exception class.
Exception Class represents something that happens not as a result of a programming error, but rather because some resource is not available or some other condition required for correct execution is not present. For example if you application is supposed to communicate with another application or computer that is not answering, this is an exception that is not caused by a bug.

When an error happens the method where the error occurred creates a special object called an exception object, this get handed off to the runtime system, the exception object contains information about the error and the state of the program when the error occurred, all this is known as throwing an exception, you can also manually throw an exception.

Once an exception has been thrown, the JVM then trys to handle the exception (catch), this means that there is code (exception handler) that identifies itself as responsible for responding to the error condition that occurred. The exception may travel up the call stack in order to find the exception handler. The call stack is a listing of program counter addresses (PCs) representing instructions (method calls) from within the program which identifies the path, the application executed to get to the current instruction or statement. If no handler is found the thread that created the error or exception dies.

Create try-catch blocks and determine how exceptions alter program flow

There are three keywords that handle a basic exception

Exception Keywords
try

is used to define a block of code in which the exception may occur. This block of code is called a guarded region (which means risky code goes here).

A try block has to have either one of the following

  • at least one catch block but can have many
  • only one finally block
  • both catch blocks and one finally block

The order must be catch block/s then finally block

catch catch clauses match a specific exception (or class of exceptions) to a block of code that handles it. Note that if there are multiple catch blocks the error is only handled by the must specific catch block, other catch blocks are then ignored.

A catch clause is not required for unchecked exceptions but is required for check exceptions. if you add a catch clause for a check exception that is never thrown from the code in the try block will clause a compile error.

An exception parameter is not final in a single exception clause but it is final if it is in a multiple clause.
finally (optional)

A finally block encloses code that will always be executed whether the an exception was thrown or not. This block of code can be useful if you want to tidy up after you have tried your risky code for an example you can closed down any network sockets, database links, etc.

You can have only one finally block for a try statement and it must be after the catch blocks if there are any.

Exception Example
defination try {
      // your risky code goes here , could be one line or many lines of code
      // remember this is know as the guarded region
}
catch (FirstExceptionType e1) {
      // your code handles the specific exception here
}
catch (SecondExceptionType | ThirdExceptionType e2) {
      // your code handles the specific exceptions here, notice we can have multiple exceptions
}
finally {
      // This code will always always execute even if an exception was not thrown, unless
      // the JVM aborts or System.exit() method is called
}

Note: that the exception variable is marked as final (in a multi-clause catch) and thus you cannot assign anything to it, a compiler error will occur if you do.

Note: If you throw an exception in a finally block regardless of other exceptions this will be the one that is thrown, all others are disreguarded
Try-Catch example with exception hierarchy
public class TryCatchExamples {
    public static void main(String[] args) {
        try {
            System.out.println("Statement 1 is just fine");
            System.out.println("Statement 2 will cause the error " + (2/0));
            System.out.println("Statement 3 is just fine");
 
        }
        catch (Throwable t) {
            t.printStackTrace(System.out);
            printErrorStructure(t);
        }
    }
    // This method will just print the hierarchy of the exception
    public static void printErrorStructure(Object o) {
        Class parent = o.getClass();
        String prefix = "";
        System.out.println("Error caught was: ");
        do {
            System.out.println(prefix + " " + parent.getName());
            prefix += "--";
            parent = parent.getSuperclass();
            if (parent == null) break;
 
        }
        while (parent.getSuperclass() != null);
    }
}

Java provides many exception classes, most of which have very descriptive names, to get information about a exception class you use the exception object itself as all exception objects are derived from the Throwable object the method printStackTrace() is inherited which provides useful information about the object. The printStackTrace() method prints the name of each method of the calling stack from the top, also a another helpful for debugging is the getMessage() method which returns the detail message string of this throwable.

Some exception classes can catch multiple conditions for an example the class IndexOutOfBoundsException has two subclasses, ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException. You may want to write one exception handler that deals with exceptions produced by either type of boundary error but you might not be concerned with which exception you actually have, of cause you can abuse this by using the Exception class to catch eveything which is considered bad programming.

catch more than one type of exception

try {
     /* some code goes here */
}
catch (IndexOutOfBoundsException e) {
   e.getMessage();
   e.printStackTrace();
}

Note: both ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException will be caught by the catch statement.

Not advised (catch-all)

try {
     /* some code goes here */
}
catch (Exception e) {
   e.getMessage();
   e.printStackTrace();
}

Note: this defeats the design objective as this could handle everything thrown at it

try-catch in a static initializer
class StaticTest {
    public static String currentMessage;

    // Initialized to 0
    public static int currentVal;

    // Static Initializer
    static {
        System.out.println("Initializing class StaticTest");
        try {
            // We force an error for demonstration purposes
            if ((10 / currentVal) > 0) {
                System.out.println("Whoops");
            }
        } catch (Exception e) {
            System.out.println("Caught the error");
        } finally {
            currentVal = 1;
        }
        currentMessage = "Inside Static Initializer";
    }

    public static void main(String[] args) {
        StaticTest st = new StaticTest();
    }
}
try-catch and constructors
(also uses code above)
import java.io.IOException;

public class InitializerExceptions {

    // Create a subclass of InitializerExceptions
    class SubClass extends InitializerExceptions {

        SubClass() throws Exception {
            super();  // Note that call to super() is redundant statement
        }
    }

    // Create an instance initializer block that throws an unchecked exception
    {
        int i = 0;
        if (i == 0) throw new IOException("Whoops");
    }

    // Constructor declares IOException in a throws clause
    // All constructors must declare a throws IOexception clause
    InitializerExceptions() throws IOException { }

    public static void main(String[] args) {
        System.out.println("Executing main()");
        System.out.println(StaticTest.currentMessage);

        try {
            InitializerExceptions ie = new InitializerExceptions();
        } catch (Exception e) {
            System.out.println("Ignoring the error, " + e.getMessage());
        }
    }
}

Create and invoke a method that throws an exception

Exceptions that a method might or might not throw have to be declared, its basically letting the world know about it. The throws keyword is used to declare an exception

Keywords
throws used in a method definition to declare the exceptions to be thrown by the method
throw used to throw an exception which hopefully will be caught
Examples
throws/throw

void myFunction() throws myException1, myException2 {      ## throws statement
   /* Some code goes here */
   throw new myException1();                               ## throw statement
}

Note: the stack above will handle the thrown exception

Throw checked and unchecled exzceptions
public class ThrowsClauseExample {
    // Custom RuntimeException
    class ACustomRuntimeException extends RuntimeException {
        ACustomRuntimeException(String message) { super(message); }
    }

    // Custom Exception (not RuntimeException)
    class ACustomCheckedException extends Exception {
        ACustomCheckedException(String message) { super(message); }
    }

    // Custom Throwable
    class ACustomThrowable extends Throwable {
        ACustomThrowable(String message) { super(message); }
    }

    // Custom Error
    class AnError extends Error {
        AnError(String message) { super(message); }
    }

    public static void main(String[] args) {
        ThrowsClauseExample t = new ThrowsClauseExample();

        // For loop allows us to test each exception thrown
        for (int i = 0; i < 4; i++) {
            try {
                switch (i) {
                    case 0:
                        t.methodOne();
                        break;
                    case 1:
                        t.methodTwo();
                        break;
                    case 2:
                        t.methodThree();
                        break;
                    case 3:
                        t.methodFour();
                        break;
                }
                // Catch clause is inside for loop, so execution of
                // for loop continues after we catch the exception
            } catch (Throwable e) {
                System.out.println("In the catch clause of main(): " + e);
            }
        }
    }

    // Unchecked Runtime Exception Thrown
    private void methodOne() { throw new ACustomRuntimeException("Error in methodOne"); }

    // Checked - must satisfy catch or specify - here we catch.
    private void methodTwo() {
        try {
            throw new ACustomCheckedException("Error in methodTwo");
        } catch (Exception e) {
            System.out.println("In the catch clause of methodTwo(): " + e);
        }
    }

    // Checked - must satisfy catch or specify - here we specify
    // in the throws clause
    private void methodThree() throws ACustomThrowable { throw new ACustomThrowable("Error in methodThree"); }

    // Unchecked Error thrown
    private void methodFour() { throw new AnError("Error in methodFour"); }
}

There are two flavours of exception, the bottomline is if a client can reasonably be expected to recover from an exception make a checked exception, if the client cannot do anything to recover from the exception make it a unchecked exception.

checked include all subtypes of Exception (excluding classes that extend RuntimeException). Checked exceptions are subject to the handle and declare rule, any method that might throw a checked exception (including methods that invoke methods that can throw a checked exception) must either declare the exception using the throws keyword or handle the exception with an appropriate try/catch.
unchecked Errors and Runtime exceptions are referred to as unchecked exceptions, thus you do not need to declare them.
Checked/Unchecked Example
check/unchecked

public class exceptionTest {

   // When you have a checked exception you need to declare to throw it
   // when you a have a unchecked exception you don't need to declare to throw it

   public static void main(String[] args) {

      // This class extends Exception a checked exception
      myCustomException1 m1 = new myCustomException1();

      // This class extends RuntimeException a uncheck exception
      myCustomException2 m2 = new myCustomException2();

      // This class throws the exception back to a calling method
      // here i use the throws keyword in a method
      myCustomException3 m3 = new myCustomException3();

      // run the checked exception method
      m1.myMethodTest();

      // run the throwing back exception method
      m3.myMethodTest();

      // run the uncheck exception method
      m2.myMethodTest();
   }
}

// a checked exception must be caught, you have to have a try and catch block
// otherwise the compiler will complain
class myCustomException1 extends Exception {

   void myMethodTest() {
      try {
         throw new Exception();
      }
      catch (Exception e) {
         e.printStackTrace();
         System.out.println("\n\n");
      }
   }
}

// a unchecked exception which does not have to be caught - notice no try and catch blocks
class myCustomException2 extends RuntimeException {
      void myMethodTest() {
         throw new NullPointerException();
      }
}

// Here we are throwing back the exception to the calling method note the keyword
// throws on the myMethodTest2 method, also note the try/catch block in the original
// method myMethodTest which will catch the thrown exception by myMethodTest2
class myCustomException3 extends Exception {

   void myMethodTest() {
      try {
         myMethodTest2();
      }
      catch (Exception e) {
         e.printStackTrace();
         System.out.println("\n\n");
      }
   }
   
   void myMethodTest2() throws Exception {
      try {
         throw new Exception();
      }
      catch (Exception e) {
         throw e;
      }
   }
}