Declaring ExceptionsJ8 Home « Declaring Exceptions

In this lesson we learn how to use the throw keyword which allows to throw exceptions from within our methods. We also investigate how to declare exceptions using the throws keyword. Before we look at using the throw and throws keywords lets refresh our memory with the different types of exceptional conditions that can occur in Java:

  • The Error class and its subclasses handle error situations from within the JVM itself and so are outside our control as programmers. As a general rule we can't recover from an Error situation and because of this we are not expected to handle an Error when it occurs.
  • The Exception class and its subclasses are what concern us more as programmers and these can be split into two categories:
    1. Runtime exceptions: Are exceptions that are not checked for by the compiler and for this reason are also known as unchecked exceptions. Generally exceptions of type RuntimeException originate from problems in our code, such as an attempt to divide by zero which gives an ArithmeticException . These sorts of errors are within our control and as such should be handled by the code itself.
    2. Checked exceptions: Are exceptions that are checked for by the compiler and if present and not declared, will give a compiler error. An example of this is a FileNotFoundException where a file we want to read may or may not be available. Whether the file is available or not is outside our control. So when we read the file, we need to handle or declare that this exception, or a superclass of it may occur.

Using the throw   Keyword Top

We can use the throw   keyword to throw exceptional conditions from within our code. At the top of the exception hierarchy is the Throwable class, which all other error and exception classes inherit from. So we can throw any subtype of the Throwable class if we want to, which includes objects of type Error, Exception and RuntimeException. The following code uses the throw   keyword to rethrow an error to a RuntimeException:


package info.java8;
/*
  A DivideByZero class
*/ 
public class DivideByZero {
    public static void main(String[] args) {
        /*
          We put the code we think might cause a problem in a try block
        */ 
        try {
            int a = 5 / 0; // JVM will not like this
        }  
        /*
          We handle the exception in a catch block and rethrow it
        */ 
        catch (ArithmeticException ex) {
            System.out.println("We caught exception: " + ex);
            throw new RuntimeException(); // No need to handle or declare Error or RuntimeException
        }  
    }
}

Save, compile and run the DivideByZero class in directory   c:\_FlowControl in the usual way.

run divide by zero and rethrow

The above screenshot shows the output of running our reworked DivideByZero class. We catch the ArithmeticException exception and rethrow it as a RuntimeException. We could also do the same for Error objects by just rethrowing with something like throw new Error();. Lets have a look at throwing a checked exception, remember these are exceptions that don't inherit from RuntimeException and are checked for by the compiler. So a checked exception needs to be handled or declared or we get a compiler error. Time to run the DivideByZero class again and this time we will throw a checked exception:


package info.java8;
/*
  A DivideByZero class
*/ 
public class DivideByZero {
    public static void main(String[] args) {
        /*
          We put the code we think might cause a problem in a try block
        */ 
        try {
            int a = 5 / 0; // JVM will not like this
        }  
        /*
          We handle the exception in a catch block and rethrow it
        */ 
        catch (ArithmeticException ex) {
            System.out.println("We caught exception: " + ex);
            throw new Exception(); // Need to handle or declare checked Exception
        }  
    }
}

Save and compile and the reworked DivideByZero class in directory   c:\_FlowControl in the usual way.

run divide by zero and rethrow2

The above screenshot shows the output of running our reworked DivideByZero class. We catch the ArithmeticException exception and rethrow it as an Exception. If you remember from our the Exception Hierarchy Diagram the Exception class is a checked exception so we need to handle or declare the exception, or we get a compiler error. This is what has happened here as we have neither handled or declared the rethrown exception. We will look at how to declare checked exceptions next.

Using the throws   Keyword Top

The compiler demands that we either handle or declare exceptions which are neither error or runtime exceptions, in other words checked exceptions. We looked at handling exceptions in the last lesson, now we will look at declaring exceptions using the throws keyword. To show this we will recode the DivideByZero class to declare that it throws an exception of type Exception.


package info.java8;
/*
  A DivideByZero class
*/ 
public class DivideByZero {
    public static void main(String[] args) throws Exception { // Declare checked exception
        try {
            int a = 5 / 0; // JVM will not like this
        }  
        /*
          We handle the exception in a catch block and rethrow it
        */ 
        catch (ArithmeticException ex) {
            System.out.println("We caught exception: " + ex);
            throw new Exception(); // Need to handle or declare checked Exception
        }  
    }
}

Save, compile and run the recoded DivideByZero class in directory   c:\_FlowControl in the usual way.

run divide by zero and rethrow3

The above screenshot shows the output of compiling and running our reworked DivideByZero class. This time the code compiles fine as we are declaring the Exception checked exception that we rethrow. We catch the ArithmeticException exception and rethrow it as an Exception and the exception propogates up the stack and our program ends.

Propogating Exceptions Up The Stack Top

In the previous example we used the throws keyword to propogate the Exception checked exception up the stack. In this example we didn't catch the exception higher up the stack and the program eventually fell over with the Exception checked exception in the main() method. In this part of the lesson we are going to learn how we can deal with chaining exceptions up the stack by declaring and ducking them. We will use a slideshow to demonstrate some calls and methods on the stack and what happens with an exception when it propogates up the stack.

stack 1 exception stack 2 exception stack 3 exception stack 4 exception stack 5 exception stack 6 exception stack 7 exception

Press the buttons below to cycle through our exception propogation explanation.


Now we have seen the slideshow, we will write the PropogateStack class.


package info.java8;
/*
  A class where we propogate an exception up the stack
*/ 
public class PropogateStack {
    public static void main(String[] args) {
        System.out.println("We are in Main().");
        PropogateStack ps = new PropogateStack();
        try {
            ps.MethodA(ps);
        }
        catch (Exception ex) {
            System.out.println("We finally catch the propogated exception in main() " + ex);
        }
        finally {
            System.out.println("Closing application.");
        }
    }
    public void MethodA(PropogateStack ps) throws Exception {  // Declare checked exception
        System.out.println("We are in MethodA().");
        ps.MethodB(ps);
    }
    public void MethodB(PropogateStack ps) throws Exception {  // Declare checked exception
        System.out.println("We are in MethodB().");
        ps.MethodC(ps);
    }
    public void MethodC(PropogateStack ps) throws Exception {  // Declare checked exception
        System.out.println("We are in MethodC().");
        try {
            int a = 5 / 0; // JVM will not like this
        } 
        catch (ArithmeticException ex) {
            System.out.println("We caught exception: " + ex);
            throw new Exception(); // Rethrow a checked Exception
        }  
    }
}

Save, compile and run the PropogateStack class in directory   c:\_FlowControl in the usual way.

run PropogateStack

The above screenshot shows the output of running the PropogateStack class and the control flow was explained in the slideshow, so we won't repeat it here.

Overridden Methods & Exceptions Top

There are a few things to remember when overriding methods that throw exceptions:

  • An overriding method can throw any Error or RuntimeException exceptions, whether these are declared in the overridden method or not.

Following is an example of the above:


package info.java8;
/*
  A Test class
*/ 
public class A  {
    public void methodA() {
        System.out.println("methodA() in class A.");
    }
}
/*
  B Test class
*/ 
public class B extends A { 
    public void methodA() throws RuntimeException {
        System.out.println("methodA() in class B.");
        throw new RuntimeException();
    }
}
/*
  Test A and B classes
*/ 
public class TestAB {
    public static void main(String[] args) {
        A a = new A();
        a.methodA();
        A b = new B();
        b.methodA();
    }
}

run AB runtime error

The above screenshot shows the output of compiling classes A, B and TestAB and then running the TestAB class. As you can see we can declare any unchecked exceptions in the overriding method, whether these are declared in the overridden method or not.

  • An overriding method must not throw any new checked exceptions or any checked exceptions that are higher up the inheritance tree than those declared in the overridden method.

Following is an example of the above:


package info.java8;
/*
  A Test class
*/ 
public class A {
    public void methodA() {
        System.out.println("methodA() in class A.");
    }
}
/*
  B Test class
*/ 
public class B extends A { 
    public void methodA() throws IllegalAccessException {
        System.out.println("methodA() in class B.");
    }
}

run AB compile error

The above screenshot shows the output of compiling classes A and B. Class B gives a compilation error as we are trying to declare an unchecked exception that has not been declared in the superclass A.

  • An overriding method can throw checked exceptions that are lower in the inheritance tree than those declared in the overridden method, or throw fewer or none of the checked exceptions that were declared in the overridden method.

Following is an example of the above:


package info.java8;
/*
  A Test class
*/ 
public class A {
    public void methodA() throws IllegalAccessException {
        System.out.println("methodA() in class A.");
    }
}
/*
  B Test class
*/ 
public class B extends A { 
    public void methodA() {
        System.out.println("methodA() in class B.");
    }
}
/*
  Test class 
*/ 
public class TestAB {
    public static void main(String[] args) {
        try {
            A a = new A();
            a.methodA();
            A b = new B();
            b.methodA();
        }
        catch (Exception ex) {
            System.out.println("Exception caught:" + ex);
        }
    }
}

run AB runtime2

The above screenshot shows the output of compiling classes A, B and TestAB and then running the TestAB class. As you can see we can declare any checked exceptions in the overridden method and the overriding method can choose whether to declare these or not.

Lesson 3 Complete

In this lesson we learnt how to use the throw keyword which allows to throw exceptions from within our methods. We also investigate how to declare exceptions using the throws keyword.

What's Next?

In the next lesson we learn how to create our own exceptions and use them in our code.