Lecture Notes: Exceptions

Related Reading: Ch. 1.8 and Ch. 6.8

Overview

Java's API makes very heavy use of throwing errors and exceptions. In this sense it is quite similar to Python (less so for C++). Formally, there is a Throwable class that serves as the base class for anything that can be thrown. There are two distinctsubclasses of Throwable:


Throwing an exception

The syntax is straightforward, with a new instance of the appropriate exception class creatd and thrown. For example, a reasonable implementation of a square root function might begin as
public static double sqrt(double val) {
  if (val < 0)
    throw new IllegalArgumentException("Must be non-negative integer");
although, as it happens, Math.sqrt does not throw any exception in this case, but instead returns the special floating point value NaN.

Catching an exception

The syntax for catching a possible error or exception is to shield the possibly offending command within a try/catch clause, as:

try {
  // one or more possible commands
} catch (exceptionType e) {
  // reaction to this exception
} catch (anotherExceptionType e2) {
  // reaction to that exception
}
For example, when attempting to open a file for input, we might write
FileInputStream f = null;
while (f == null) {
  String filename = scanner.next();    // assuming scanner is appropriate Scanner
  try {
    f = new FileInputStream(filename);
  } catch (FileNotFoundException e) {
    System.out.println("Could not find file " + filename);
  }
}

Optionally, a try clause may also end with a finally clause. That body will be executed in all situation, that is immediately after the successful completion of the try body, or after the catching of any declared exceptions. The book gives an example of the use of a finally clause to close a file reader.


Exception hierarchy and checked exceptions

Java defines a further refinement of Exception subclasses, by making a distinction between a RuntimeException hierarchy, and all other exceptions. In general, something is a RuntimeException if it is more easily preventable by proper programming techniques. For example, and ArrayIndexOutOfBoundsException is a subtype of RuntimeException as programming logic can be used to avoid causing such an exception.

An example of a class of exceptions that do not qualify as being a RuntimeException is the IOException class. Those problems tend to be caused by something external to the program logic, such as a file that cannot be found, open, or read.

The distinction between RuntimeException and others is an important one in the language definition, as RuntimeException types are treated as "unchecked" exceptions, while others are "checked" exceptions.


Throws declaration

The significance of the distinction between checked and unchecked exceptions is that a function's signature must expclitly declare any type of checked exception that might result from a call to the function (unchecked exceptions need not be declared). We note that the declared exceptions are not just for those directly thrown from within the function body, but also those that might be thrown by other function calls that are made from within the body of the function in question. An example of such a declaration from the text book is:
public void read(String filename) throws IOException, ClassNotFoundException {
  // ...
}

The signficance of such required declaration of throwables is that it allows a caller to know precisely what types of checked exceptions might occur, and therefore a suggestion that such exceptions might be caught from the calling context. So if one function makes a call to one with declared throwables, the calling function must either guard such statements in a try/catch structure, or else add declarations in its own signature to warn against the possibility of a checked exception being propogated.


Last modified: Monday, 05 September 2011