Java checked exceptions: how do i solve this?

E

ennioennioennio

Hi,
One of my biggest troubles is how to sort out java checked exceptions.
I'd like to understand how to "correctly" implement them when
"delegating" roles.
Here i will explain an example in detail.

I am developing the class Node that represents a node of a tree: it
has the possibility to load its children lazily after setting its
ChildrenLoadingStrategy. The core methods in this class are
getChildren() and getFather().

public abstract class Node {
private ChildrenLoadingStrategy strategy = null;
public setChildrenLoadingStrategy(ChildrenLoadingStrategy strategy) {
this.strategy = strategy;
}
public List<Node> getChildren() {
if (strategy != null) {
strategy.loadChildren(this);
}
}
public void addChild(Node childNode) {...}
protected void setFather(Node nodeFather) { //this method is called
by addChild() }
public Node getFather() {...}
public List<Node> getBrothers() {...}
[*] plus lots of other methods that contains calls to getChildren()

}
interface ChildrenLoadingStrategy {
void loadChildren(Node node); //calls node.addChild()
}


Briefly: The Node class delegates getChildren() to the
ChildrenLoadingStrategy. Maybe this is not "strictly" exact, probably
the design is not perfect, but it's just an example.

Suppose that the an implementation of
ChildrenLoadingStrategy.loadChildren() contains SQL code. And
SQLExceptions.
Suppose that the another implementation of
ChildrenLoadingStrategy.loadChildren() contains I/O code. And
IOExceptions.
How do i reflect these exceptions in the Node.getChildren() method?

Solution 1: declare a brand new Exception that encanpsulates the inner
ones.
void loadChildren(Node node) throws ChildrenLoadingException {
try {
...
} catch(Exception e) {
throws ChildrenLoadingException(e);
}
}
public List<Node> getChildren() throws ChildrenLoadingException {...}
public List<Node> anyOtherMethodInNodeThatCallsGetChildren() throws
ChildrenLoadingException {...}
Comment: Do you like it? i don't. Somehow it "stinks"

Solution 2: declare ANY Exception
void loadChildren(Node node) throws Exception {...}
public List<Node> getChildren() throws Exception {...}
public List<Node> anyOtherMethodInNodeThatCallsGetChildren() throws
Exception {...}
Comment: mmmmm.

Solution 3: say goodbye to checked exceptions
void loadChildren(Node node) {
try {
...
} catch(Exception e) {
throws new RuntimeException(e);
}
}
public List<Node> getChildren() {...}
public List<Node> anyOtherMethodInNodeThatCallsGetChildren() {...}
Comment: Terrific! Or maybe better than solution 2?


What can you suggest me about solution 1, 2 or 3?
Have u got any other solution?
Thank you very much
 
B

Ben Phillips

Solution 1: declare a brand new Exception that encanpsulates the inner
ones.
void loadChildren(Node node) throws ChildrenLoadingException {
What can you suggest me about solution 1, 2 or 3?

Use solution 1 ... throw new ChildrenLoadingException(detailMessage,
originalException) (punts to the Exception(String, Exception) constructor).
 
J

Joshua Cranmer

Suppose that the an implementation of
ChildrenLoadingStrategy.loadChildren() contains SQL code. And
SQLExceptions.
Suppose that the another implementation of
ChildrenLoadingStrategy.loadChildren() contains I/O code. And
IOExceptions.
How do i reflect these exceptions in the Node.getChildren() method?

To answer this question, think about the design of your code:
1. What does an SQLException or IOException mean in your case? Is it:
a. User validation error? (Notifying the GUI and refusing to
continue is the best option here)
b. An expected event? (Rewriting it so it isn't expected is the best
option here)
c. A recoverable error? (Propagating a checked exception is best here).
d. A fatal error? (Dieing and logging the error is best here).

Solution 1: declare a brand new Exception that encanpsulates the inner
ones.
void loadChildren(Node node) throws ChildrenLoadingException {
try {
...
} catch(Exception e) {
throws ChildrenLoadingException(e);
}
}
public List<Node> getChildren() throws ChildrenLoadingException {...}
public List<Node> anyOtherMethodInNodeThatCallsGetChildren() throws
ChildrenLoadingException {...}
Comment: Do you like it? i don't. Somehow it "stinks"

This is the preferred method of recovery, but it generally helps to keep
these propagating errors as close to the point of failure as possible.

Solution 2: declare ANY Exception
void loadChildren(Node node) throws Exception {...}
public List<Node> getChildren() throws Exception {...}
public List<Node> anyOtherMethodInNodeThatCallsGetChildren() throws
Exception {...}
Comment: mmmmm.

Horrible and defeats the purpose of checked exceptions.
Solution 3: say goodbye to checked exceptions
void loadChildren(Node node) {
try {
...
} catch(Exception e) {
throws new RuntimeException(e);
}
}
public List<Node> getChildren() {...}
public List<Node> anyOtherMethodInNodeThatCallsGetChildren() {...}
Comment: Terrific! Or maybe better than solution 2?

Even worse than solution 2, by far the worst of all: by the points at
which you start handling recovery, it can become impossible to handle
developer bugs (which are those that tend to subclass RuntimeException:
ArrayIndexOutOfBoundsException, etc.) from real bugs that need error
handling.
What can you suggest me about solution 1, 2 or 3?

Pick solution 1. Purge solutions 2 and 3 from your mind immediately.
They should not be used in any production code.
 
J

Joshua Cranmer

Joshua said:
Pick solution 1. Purge solutions 2 and 3 from your mind immediately.
They should not be used in any production code.

(Hit "Send" too quickly)

Java has, IMO, the best error-handling exception system out there. [*]
The notion of checked exceptions is perhaps its best feature--it forces
developers to actually properly handle errors where they might blithely
be ignored. In addition, checked exceptions makes the documentation of
errors a lot easer (quick: what error does Python throw if it tries to
read from a file that is on an NFS share that has been unmounted?).

[*] Well, some of the implementation is poor: the close() method of an
IO stream can throw an IOException, which makes handling resource clean
up painful.
 
R

Roedy Green

How do i reflect these exceptions in the Node.getChildren() method?

Probably the easiest way to handle this when you don't know what sort
of mess the implementor might throw is to make up a new Exception, and
have the implementor catch any miscellaneous exceptions and wrap them
in the new standard catch-all Exception and rethrow that.
 
L

Lew

(e-mail address removed) wrote,
Roedy said:
Probably the easiest way to handle this when you don't know what sort
of mess the implementor might throw is to make up a new Exception, and
have the implementor catch any miscellaneous exceptions and wrap them
in the new standard catch-all Exception and rethrow that.

Good advice, and to wrap them use the idiom that Ben Phillips explained:
Use solution 1 ...
throw new ChildrenLoadingException(detailMessage, originalException)
(punts to the Exception(String, Exception) constructor).

I repeat it because it's such good advice, and because it provides a detail
for the implementation of Roedy's advice. All the answers in this thread
coordinate with each other:

Joshua Cranmer:
think about the design of your code:
1. What does an SQLException or IOException mean in your case?
and
The notion of checked exceptions ...
... forces developers to actually properly handle errors
where they might blithely be ignored. In addition,
checked exceptions makes the documentation of errors a lot easier

The unifying notion is that checked exceptions are an API signature mechanism
to provide meaningful error recovery to client invocations.

The checked exception should have meaning appropriate to the component or
system layer that (re)throws it. For example, a Data Access Object
(DAO)-layer class likely would receive IOExceptions, particularly
SQLExceptions from the APIs it invokes. Those exceptions have meaning to it,
because a DAO "knows" about such things. What it throws is a "Data Access"
problem to upstream clients - perhaps derived from IOException but certainly
in its own, application-specific domain of discourse. Thus one would rethrow
new DataAccessException( "domain-meaningful message", ioExcFromDownstream )
as Ben showed.

Good encapsulation has the exception carry meaning in terms the invoker
understands, not what goes on under the API's covers.
 
R

Roedy Green

Probably the easiest way to handle this when you don't know what sort
of mess the implementor might throw is to make up a new Exception, and
have the implementor catch any miscellaneous exceptions and wrap them
in the new standard catch-all Exception and rethrow that.

I should refine that advice. If you have a non-trivial interface, you
probably should devise a set of Exceptions (all derived from the same
root) that define what went wrong in terms that make sense relative to
the services offered by the interface. That lets the caller treat them
collectively or individually. They need to be defined at a higher
level than the exceptions being raised inside the implementation. They
have to make sense no matter what the implementation.

Imagine devising a database interface. Your Exceptions would talk
about the database tables and rows, not about file/io screwing up.
 
S

Stefan Ram

Roedy Green said:
If you have a non-trivial interface, you probably should devise
a set of Exceptions

The exceptions can also be type parameters:

interface Example
< E1 extends java.lang.Throwable, E2 extends java.lang.Throwable >
{ void example() throws E1, E2; }

When an implementation does not need to declare
two exceptions, it can still use this interface
by giving »java.lang.RuntimeException« as type
arguments:

class ExcampleImplementation
implements Example< java.lang.RuntimeException, java.lang.RuntimeException >
{ public void example(){} }

This posting is based on ideas published
in de.comp.lang.java by Ralf Ullrich.
 
M

Mike Schilling

Joshua Cranmer said:
Joshua said:
Pick solution 1. Purge solutions 2 and 3 from your mind immediately. They
should not be used in any production code.

(Hit "Send" too quickly)

Java has, IMO, the best error-handling exception system out there. [*] The
notion of checked exceptions is perhaps its best feature--it forces
developers to actually properly handle errors where they might blithely be
ignored. In addition, checked exceptions makes the documentation of errors
a lot easer (quick: what error does Python throw if it tries to read from
a file that is on an NFS share that has been unmounted?).

[*] Well, some of the implementation is poor: the close() method of an IO
stream can throw an IOException, which makes handling resource clean up
painful.

It's a bit useless for InputStream.close() to throw an exception; if you're
done reading from the stream, you presumably don't care that you, say, lost
contact with an NFS mount. But if an OutputStream has been buffering output
that close() can't flush properly, how would you prefer to be notified of
that?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top