It is designed in Java that I get a Throwable
object if I invoke getCause()
on an Exception
.
I understand that getCause()
is simply inherited from Throwable
and I know that Throwable
can be either an Error
or an Exception
, but a programmer generally should work only on the Exception
level without dealing with Throwable
/Error
classes.
What was the reason in the Java exception hierarchy design to, for example, not include getCause()
in the Exception
class that would return an Exception
object?
Here is an illustration of the inconvenience taken from Java Concurrency In Practice (Brian Goetz):
public class Preloader {
private final FutureTask<ProductInfo> future =
new FutureTask<ProductInfo>(new Callable<ProductInfo>() {
public ProductInfo call() throws DataLoadException {
return loadProductInfo();
}
});
private final Thread thread = new Thread(future);
public void start() { thread.start(); }
public ProductInfo get()
throws DataLoadException, InterruptedException {
try {
return future.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof DataLoadException)
throw (DataLoadException) cause;
else
throw launderThrowable(cause);
}
}
}
It is said in the book:
...but also because the cause of the
ExecutionException
is returned as aThrowable
, which is inconvenient to deal with...
And in launderThrowable()
it is dealt with rethrowing Error
right away (because we don't want to deal with it) and returning RuntimeException
:
public static RuntimeException launderThrowable(Throwable t) {
if (t instanceof RuntimeException)
return (RuntimeException) t;
else if (t instanceof Error)
throw (Error) t;
else
throw new IllegalStateException("Not unchecked", t);
}