When the TRy block executes its return, the finally block is entered with the "reason" of returning the
value 1. However, inside the finally block the value 2 is returned, so the initial intention is forgotten. In
fact, if any of the other code in the try block had thrown an exception, the result would still be to return 2. If
the finally block did not return a value but simply fell out the bottom, the "return the value 1" reason
would be remembered and carried out.
12.5. Exception Chaining
Exceptions sometimes are caused by other exceptions. In "A Quick Tour", Section 1.14 on page 32, you saw
an example where this was true:
public double[] getDataSet(String setName)
throws BadDataSetException
{
String file = setName + ".dset";
FileInputStream in = null;
try {
in = new FileInputStream(file);
return readDataSet(in);
} catch (IOException e) {
throw new BadDataSetException();
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
; // ignore: we either read the data OK
// or we're throwing BadDataSetException
}
}
}
// ... definition of readDataSet ...
This method throws a BadDataSetException on any I/O exception or data format error. The problem is
that any information about the original exception is lost, and it might be a needed clue to fixing the problem.
Replacing exceptions with other ones is an important way to raise the level of abstraction. To any code
invoking the above method, all failures can be recovered from in the same way. The particulars of the failure
probably don't much matter to what the program will do, which is to handle the failure of the data file. But
humans fixing the problem can require knowledge of the exact failure, so they will want to have that
information availablesee "Stack Traces" on page 294.
Situations like this are common enough that the exception mechanism includes the notion of one exception
being caused by another exception. The initCause method, defined in Throwable, sets one exception's
cause to be the exception object passed as a parameter. For example, the previous example can have its
IOException catch clause rewritten as:
} catch (IOException e) {
BadDataSetException bdse = new BadDataSetException();
bdse.initCause(e);
throw bdse;
} finally {
// ...
}