THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

Here initCause is used to remember the exception that made the data bad. This means that the invoking
code can handle all bad data simply with one exception handler but still know the kind of exception that
caused the underlying problem. The invoking code can use the getCause method to retrieve the exception.


The example can be simplified further by writing BadDataSetException to expect to have a cause, at
least some of the time, and so provide a constructor to accept that cause if it is known. The idiomatic way to
define a new exception class is to provide at least the following four constructor formsor variants thereof that
deal with exception specific data:


class BadDataSetException extends Exception {
public BadDataSetException() {}


public BadDataSetException(String details) {
super(details);
}


public BadDataSetException(Throwable cause) {
super(cause);
}


public BadDataSetException(String details,
Throwable cause) {
super(details, cause);
}
}


Now the catch clause in the example simply becomes:


} catch (IOException e) {
throw new BadDataSetException(e);
} finally {
// ...
}


Not all exception classes provide cause-taking constructors, but all support the initCause method. To
make it easier to use initCause with such exception classes, it returns the exception instance that it is
invoked on. The idea is that you can use it like this:


throw new BadDataSetException().initCause(e); // Error?


The only problem is that this will nearly always result in a compile-time error: initCause returns a
THRowable instance, and you can only throw a THRowable if your method's throw clause lists
Throwablewhich it rarely, if ever, should! Consequently, you have to modify the above, to cast the
Throwable back to the actual exception type you are creating:


throw (BadDataSetException)
new BadDataSetException().initCause(e);

Free download pdf