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
Artima Forums.
Message:
Further Thinking
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 > Exceptions. > 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 StackOverflow. 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?
Replies:
|