The decision to make RemoteException a
checked exception and requiring remote
methods to list the exception in its
throws clause is not a religious one.
The decision is based on how to make
distributed computing reliable. This
question comes up every once in a
while on our users list. I have a
detailed response that I posted a
while ago. Here it is if you are
interested. I couldn't find it in the
rmi-users archive, so I included it
below.
I'd like to address the rationale for
making RemoteException a checked
Exception, rather than a
RuntimeException.
1) networks aren't reliable
I wish that they were, but in fact,
they're not. Every network has
transient failures. You can build in
network redundancy, but the fact is
that most networks don't have that.
Intranets have transient failures, as
does the Internet. So, every RPC made,
is subject to a failure. The types of
failures may not have anything to do
with the "network", per se; if your
server runs out of file descriptors,
your client will get a connect
exception. This isn't a network
failure, in the sense of the network
being broken; your server is in a
transient state of being resource
starved.
RMI is not designed to only handle the
limited case that the whole network
crashes when a single machine crashes.
Such a network would be considered
reliable, either everything is up or
everything is down--there is no
partial failure. RMI is targetted for
a more general audience.
2) RPC failure can't be hidden from
the client
Partial failure is a fact of
distributed programming; these
failures can't be hidden to the
program. A failure shows up in the
client, whether the exception is
checked or unchecked exception, it
still shows up. So, how should such
failures be indicated to the client?
3) checked exceptions foster more
robust programs
There was a time when Oak and the
earliest version of Java did not have
checked exceptions. Exception handling
was advisory, and it was an unsafe
world out there. It was our group (Jim
Waldo and me in particular :-) that
recommended that there be exceptions
checked by the compiler. Jim was quite
persuasive in his arguments, telling
of a world where robust code would
reign. After some consideration, Java
was retooled to have checked
exceptions. Only those exceptions for
which there was no recovery or reflect
application errors would be unchecked
(e.g., OutOfMemoryError,
NullPointerException respectively).
And the world was safe again.
Imagine the Java engineers' surprise
when many exceptions in the Java API
and compiler were changed from
unchecked to checked, and the compiler
enforced the distinction, they
uncovered bugs in the implementations!
So, the best efforts at handling error
conditions, however well intentioned,
was not good enough. That compiler is
useful for something :-)
4) RemoteException should be a checked
exception
Ok, so back on track here. Since a
RemoteException is a fact of life in a
RPC call (see #1, #2) and checked
exceptions force you to write safe
code (#3), we thought that making
RemoteException a checked exception
was a good idea. Writing robust
distributed programs is hard enough,
without having the compiler to help
you with exceptions.
So, some might argue that a
RemoteException is a like an
OutOfMemoryError; your program should
fall over dead if a remote call fails.
I disagree with this point. Yes, in
some cases, there is no recovery from
a RemoteException; but if you are
writing a reliable distributed
program, your client needs to catch
failures and retry appropriately.
Perhaps you need to contact another
server, or abort a transaction of some
sort. If the RemoteException is not
handled, it will percolate up and
crash your client (yuk).
Others have stated that there are some
remote interfaces that are used in
both the local case and the remote
case and the client should not have to
deal with the exceptions in the local
case, so RemoteException should not
have to be in a throws clause and
handling it should not be mandatory.
Now, if we allowed remote interface
methods to omit RemoteException and
had an "rmic" switch to generate stubs
that would throw an unchecked
RemoteException, the client has no
choice in the matter. The decision of
exception handling should remain with
the client. If you define an interface
that only throws unchecked exceptions
you can never write a client that
wants compiler help in dealing with
those exceptions. We have already
seen from the above example that
checked exceptions fosters robust
code.
Another issue that has popped up now
and again is that developers need to
simply translate local interfaces and
use them as remote interfaces. This
may work for a small set of cases, but
if the interface was not designed with
concurrency and partial failure and
call latency in mind, the protocol
captured by the interface may not be
appropriate to use in the distributed
case. Is enough information passed in
those operations to make the
operations idempotent? Perhaps, but
most likely not.
Putting RemoteException in every
throws clause may seem like a pain,
but its the price to pay for writing
robust distributed applications.
-- Ann Wollrath