In Ice for C++ (and other language mappings), all Ice exceptions derive from a common base class. For example, in C++, we have
Ice::Exception at the root, with derived classes
Ice::UserException. In turn, all the Ice run-time exceptions derive from
LocalException, and all the Ice user exceptions derive from
The advantage of having a common base class for user- and run-time exceptions is that you can catch all Ice exceptions with a single exception handler:
In Java, we also have
Ice.LocalException derived from
Ice.UserException does not derive from
Ice.Exception. If you want to catch all Ice exceptions, you must write two separate exception handlers:
So, why this difference? The reason is Java's checked exception model. (People either hate or love this model — Kevlin Henney (among many others) provides an interesting discussion of its trade-offs.)
Java distinguishes between two kinds of exceptions, checked exceptions and unchecked ones. For checked exceptions, the language, at compile time, enforces that a method must declare all checked exceptions that it can possibly throw in a separate
throws clause. This includes any exceptions that (recursively) might be thrown by any called methods. On the other hand, for unchecked exceptions (which are exceptions that derive from
java.lang.Error), the language does not require you to list them explicitly in a
throws clause — any method can throw an unchecked exception at any time.
Unchecked exceptions were added to the language out of necessity. For example, imagine the consequences of
NullPointerException being a checked exception: either every method would need a
throws clause for this exception, or the body of every method would have to catch and swallow this exception (or translate it to some other exception that can be thrown). Clearly, this would be quite intrusive and messy.
Ice follows the Java philosophy: Ice run-time exceptions are unchecked exceptions and Ice user exceptions are checked exceptions. This allows you to write code without eternally having to write
throws clauses for Ice run-time exceptions, while still enforcing that your methods correctly deal with user exceptions. The down-side of this approach that you need two exception handlers if you want to catch both Ice user- and run-time exceptions. Note that you can catch all Ice exceptions with a single exception handler:
Sure enough, this catches all Ice user- and run-time exceptions, but the glitch is that it catches everything else as well, including exceptions that have nothing to do with Ice. As a work-around, you could add further processing in the handler to determine whether the exception is not an Ice exception and, if so, rethrow it:
However, most people would agree that this rather obscures the issue; it is clearer and simpler to write two separate exception handlers in the few places in the code where you need to catch both Ice user- and run-time exceptions.