Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / September 2007

Tip: Looking for answers? Try searching our database.

Java checked exceptions: how do i solve this?

Thread view: 
ennioennioennio@gmail.com - 22 Sep 2007 16:11 GMT
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
Ben Phillips - 22 Sep 2007 16:20 GMT
> 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).
Joshua Cranmer - 22 Sep 2007 16:34 GMT
> Suppose that the an implementation of
> ChildrenLoadingStrategy.loadChildren() contains SQL code. And
[quoted text clipped - 3 lines]
> 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.
[quoted text clipped - 9 lines]
> 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) {
[quoted text clipped - 7 lines]
>     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.

Signature

Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

Joshua Cranmer - 22 Sep 2007 16:40 GMT
>> 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.

(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.

Signature

Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

Mike Schilling - 23 Sep 2007 10:12 GMT
>>> What can you suggest me about solution 1, 2 or 3?
>>
[quoted text clipped - 13 lines]
> 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?
Roedy Green - 22 Sep 2007 20:37 GMT
>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.
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Lew - 22 Sep 2007 20:53 GMT
ennioennioennio@gmail.com wrote,
>> 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.

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.

Signature

Lew

Roedy Green - 22 Sep 2007 21:39 GMT
On Sat, 22 Sep 2007 19:37:27 GMT, Roedy Green
<see_website@mindprod.com.invalid> wrote, quoted or indirectly quoted
someone who 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.

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.

Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Stefan Ram - 22 Sep 2007 21:55 GMT
>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.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.