Universidad Carlos III de Madrid

Ingeniería de Telecomunicación

Enero-Mayo 2010 / January-May 2010

Brief introduction to exceptions in Java

Exceptions allow methods to report to the calling code about any issues, errors or anomalous situations generated during its execution.

For example, let's suppose a method that receives a postal code and returns the name of the town that it belongs to. In the normal case that the postal code is correct, the method would just return the name of the town. In the case that the received postal code does not exist or has an incorrect format, the method would notify it throwing an exception. An exception in Java is an object of the Exception class or any of its subclasses.

Declaring our own exception classes

Java provides many predefined exception classes for certain situations, such as for example IOException for errors related to input/output operations, such as reading files.

For our own programs, sometimes it is useful to create our own ad-hoc exceptions. To do so, we have to declare a new class that inherits from Exception. For example:

public class BadPostCodeException extends Exception {

    public BadPostCodeException() {
        super();
    }

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

We do not usually need to declare new attributes or methods, apart from the constructors.

How exceptions are thrown

When inside a method we need to throw and exception, we will use the throw keyword, followed by an instance of the exception class to throw. For example:

if (postCode.length() != 5) {
    throw new BadPostCodeException("Postcodes must have 5 digits");
}
for (int i = 0; i < postCode.length(); i++) {
    if (!Character.isDigit(postCode.charAt(i))) {
        throw new BadPostCodeException("Postcodes can only contain digits");
    }
}
City city = lookupPostCode(postCode);
if (city == null) {
    throw new BadPostCodeException("Postcode not in database: " + postCode);
}

Except for a special subset of exceptions, in general a method that can (potentially) throw an exception must declare it explicitely, using the throws keyword (pay attention to the final "s", and don't confuse it with throw) followed by the name of the exception class that it may throw:

public class PostCodeManager {
(...)

    public String town(String postCode) throws BadPostCodeException {
        if (postCode.length() != 5) {
            throw new BadPostCodeException("Postcodes must have 5 digits");
        }
        for (int i = 0; i < postCode.length(); i++) {
            if (!Character.isDigit(postCode.charAt(i))) {
                throw new BadPostCodeException("Postcodes can only contain digits");
            }
        }
        City city = lookupPostCode(postCode);
        if (city == null) {
            throw new BadPostCodeException("Postcode not in database: " + postCode);
        }
        (...)
    }
(...)
}

If the method can throw exceptions of different classes, all the exception class names must be explicitely stated in the declaration, separated by commas, following one only throws.

What happens when an exception is thrown

When a exception happens, the virtual machine interrupts the normal execution flow of the program, and searches for a block of code appropriate for dealing with the situation. If such piece of code is not found in the current method, the exception propagates (is thrown) to the invoking method, and searches for the code to deal with the exception there. If that method don't provide the appropriate code either, the exception will propagate again to the following invoking method, and so on.

This section explains the case when a method does not provide the code appropriate for dealing with an exception. As explained before, in this case the exception propagates (is thrown) to the calling method. A method that does not provides code for dealing with the exception must declare that it may throw it with the throws keyword, as explained in the previous section:

public class Location {
(...)
    private String postCode;

    public String townAsString() throws BadPostCodeException {
        PostCodeManager manager = new PostCodeManager();
        String town = manager.town(postCode);
        return postCode + " " + town;
    }
(...)
}

In the example, the call to the town method may potentially throw an exception. The townAsString method does not contain code for treating it. In consequence, the exception would propagate through it (it would be thrown again to the method calling townAsString), thus must declare that it may throw it, as shown in the example.

If during the call to town an exception happens, such exception will be propagated to the method that has called to townAsString.

The exception will continue propagating through the call stack, until it is captured (treated) in a method. If the main method is reached, and it does not provide any code for dealing with it either, the virtual machine will interrupt the execution flow of the program and show the user, usually on the console, the message of the exception and the place in the program where it happened.

How an exception is treated

A method can decide to capture an exception if it is logic to put in such method the code that process it appropriately. For capturing an exception, a try/catch block is used:

try {
    // code where the exception may happen
} catch (ExceptionClass e) {
    // code that process the exception situation
}

When the exception happens in the try block, the execution is interrupted and the code in the catch block starts executing. Once finalised the catch block, the execution continues with the code following the try/catch block. Usually, it continues also at that point when the try code ends without exceptions.

An alternative implementation of townAsString in which the exception is captured is shown below:

public class Location {
(...)
    private String postCode;

    public String townAsString() {
        String result;
        PostCodeManager manager = new PostCodeManager();
        try {
            String town = manager.town(postCode);
            result = postCode + " " + town;
        } catch (BadPostCodeException e) {
            result = "Unknown location at postcode " + postCode;
	}
        return result;
    }
(...)
}

If an exception is generated inside the town method, the execution of the code in the try block is interrupted, and thus the result = postCode + " " + town instruction is no longer executed, but the program jumps to the catch block and executes the code inside it. The return result instruction is always executed, independently of having or not an exception, because it is outside and following the try/catch block.

Pay attention that the townAsString does not declare in this case that it throws the exception. As it captures the exception, it no longer propagates through it.