This page contains an archived post to the Design Forum (formerly called the Flexible Java Forum) made prior to February 25, 2002.
If you wish to participate in discussions, please visit the new
Posted by Bill Venners on April 26, 1999 at 10:46 AM
> > The only problem that seems to plague the observer idiom in Java is
> > the throwing of errors in the listeners. What is your recommendation
> > for the cases where the listeners fail to catch errors and it
> > ends up blowing up the event generator? Would you typically
> > catch and ignore or let the listener blow you up.
> This is a good point. I'll have to think about this one, and
> would welcome other people's thoughts in the mean time. It
> seems to me on first glance that all my fireXXX() method is
> supposed to be responsible for is to deliver the event
> message to each listener. If a listener has a bug or some
> problem which results in an exception, my first inclination
> is to catch and ignore the Exception and then continue
> passing the event to the other listeners. I wouldn't catch
> Errors, but I think I might just be inclined to catch all
> The trouble with ignoring an exception is that then when the
> fireXXX method is done passing along the message, should it
> report back to its caller with some kind of exception? And
> what exception?
> I think what I lack here is clarity of the fireXXX's contract
> and the listener method's contract. I'll think about this
> one and post again later.
If you take a look at the TelephoneListener interface, you'll see
that the notification methods, telephoneRang() and
telephoneAnswered() don't have throws clauses. This means that
objects that implement this interface can't throw any exceptions
from those methods except RuntimeExceptions, which aren't
checked, and Errors.
My opinion is that Errors shouldn't be caught anyway, and
should usually result in the death of the thread. Errors
indicate a catastrophic problem, such as OutOfMemory or
RuntimeErrors, on the other hand, usually indicate a software
bug. Since listeners can't throw checked exceptions because
of the signature of the notification methods in the
TelephoneListener interface, the "contract" between the event
source object and the listener is that the notification methods
should not throw any exceptions. (The other part of the contract
is that the notification methods should return "quickly.")
So if the event source surrounds its invocation of the
notification methods with a try block, and catches all
RuntimeExceptions so that it can make sure it notifies all
listeners, it is basically trying to be robust in the face
of software bugs in the listener objects.
Given that the Event Generator idiom enables the event source
to know know anything about the listner objects other than they
implement the listener interface, it make sense to me that
event generators would implement this level of robustness against
software bugs in the listeners.
As far as what the fire() method should return when it has
caught and ignored one or more runtime exceptions, I can see
two possibilities. One is it can just bury them and return
normally. This makes some sense to me because I have no idea
what the caller is going to want to do in the case of a buggy
listener. (Perhaps the fire() method could print out a message
to an error log.)
Alternatively, the fire() method could collect the runtime
exceptions it catches and ignores and throw an exception that
is a "bucket" of the caught runtime exceptions, along with
some other information about the listener(s) that failed.
The question this issue brings to my mind is to what extent
should I program defensively against classes that are "breaking
their contract". It seems my program will be more robust if
I have some strategy for dealing with software bugs in listeners,
but how do I know that the whole program isn't going to be
broken if a listner has a bug in it. Any thoughts?