Java Language Throwing an exception


Example

The following example shows the basics of throwing an exception:

public void checkNumber(int number) throws IllegalArgumentException {
    if (number < 0) {
        throw new IllegalArgumentException("Number must be positive: " + number);
    }
}

The exception is thrown on the 3rd line. This statement can be broken down into two parts:

  • new IllegalArgumentException(...) is creating an instance of the IllegalArgumentException class, with a message that describes the error that exception is reporting.

  • throw ... is then throwing the exception object.

When the exception is thrown, it causes the enclosing statements to terminate abnormally until the exception is handled. This is described in other examples.

It is good practice to both create and throw the exception object in a single statement, as shown above. It is also good practice to include a meaningful error message in the exception to help the programmer to understand the cause of the problem. However, this is not necessarily the message that you should be showing to the end user. (For a start, Java has no direct support for internationalizing exception messages.)

There are a couple more points to be made:

  • We have declared the checkNumber as throws IllegalArgumentException. This was not strictly necessary, since IllegalArgumentException is a checked exception; see The Java Exception Hierarchy - Unchecked and Checked Exceptions. However, it is good practice to do this, and also to include the exceptions thrown a method's javadoc comments.

  • Code immediately after a throw statement is unreachable. Hence if we wrote this:

     throw new IllegalArgumentException("it is bad");
     return;
    

    the compiler would report a compilation error for the return statement.

Exception chaining

Many standard exceptions have a constructor with a second cause argument in addition to the conventional message argument. The cause allows you to chain exceptions. Here is an example.

First we define an unchecked exception that our application is going throw when it encounters a non-recoverable error. Note that we have included a constructor that accepts a cause argument.

    public class AppErrorException extends RuntimeException {
        public AppErrorException() {
            super();
        }

        public AppErrorException(String message) {
            super(message);
        }

        public AppErrorException(String message, Throwable cause) {
            super(message, cause);
        }
    }

Next, here is some code that illustrates exception chaining.

    public String readFirstLine(String file) throws AppErrorException {
        try (Reader r = new BufferedReader(new FileReader(file))) {
            String line = r.readLine();
            if (line != null) {
                return line;
            } else {
                throw new AppErrorException("File is empty: " + file);
            }
        } catch (IOException ex) {
            throw new AppErrorException("Cannot read file: " + file, ex);
        }
    }

The throw within the try block detects a problem and reports it via an exception with a simple message. By contrast, the throw within the catch block is handling the IOException by wrapping it in a new (checked) exception. However, it is not throwing away the original exception. By passing the IOException as the cause, we record it so that it can be printed in the stacktrace, as explained in Creating and reading stacktraces.