views:

288

answers:

3

I would like to get a second opinion on how to handle Exceptions within "events" (key input, screen update etc). In this case I have control over the event-sender.

So a module is set to handle an event (it implements a listener interface, and is registered against an event sender):

public void DefaultSet ( CardData oldDefault, CardData newDefault )
{
}

The event sender is simply:

     for ( Enumeration e = listeners.elements(); e.hasMoreElements(); )
  {
   RetrieverListener thisListener = (RetrieverListener) e.nextElement();
   thisListener.DefaultSet( oldDefault, newDefault );
  }

So if/when something goes wrong in the receiver:

  • Should I try to cope with the exception there, and never throw anything back to the sender? Sometimes the listeners don't have the "context" to handle an error correctly, is that right?

  • Is it frowned on to throw an exception back to an event-sending module, to be handled in a documented way? e.g. "Throwing an IOException will result in a reset.. ". This seems non-standard from the javadocs I have read.

  • Should I just log and ignore the exception when something goes wrong & nothing can be done about it?

+1  A: 

When nothing can be done about you should log and send a message to the user. If something goes wrong that may damage data or give wrong results if you can't recover you should close the application.

Daniel Moura
+3  A: 

The Java convention is that listener methods do not throw exceptions. Obviously, programming errors might make a listener throw a RuntimeException, but there's no way the event source can recover from that because it will have left the program's objects in some unknown, maybe inconsistent state.

It is therefore up to the listener to catch checked exceptions and either recover from them (roll back a transaction, for example) or report them to some other object. I often use an ErrorHandler interface that looks something like:

public interface ErrorHandler {
    public void errorOccurred(String whatIWasTryingToDo, Exception failure);
}

An event listener tells its ErrorHandler about errors that have occurred.

public class SomeClass implements SomeKindOfListener 
    private final ErrorHandler errorHandler;
    ... other fields ...

    public SomeClass(ErrorHandler errorHandler, ... other parameters ... ) {
        this.errorHandler = errorHandler;
        ...
    }

    public void listenerCallback(SomeEvent e) {
        try {
            ... do something that might fail ...
        }
        catch (SomeKindOfException e) {
            errorHandler.errorOccurred("trying to wiggle the widget", e);
        }
    }         
}

I initialise event listeners with an implementation of this that handles the failure in whatever way makes sense at that point in the application. It might pop up a dialog, show a flashing error icon in the status bar, log an audit message, or abort the process, for example.

Nat
You have to design the system to make the listeners able to deal with the error. An exception will unwind the stack back to the listener. The listener has been invoked by something that cannot possibly know how to react to the exception -- a button called on the Swing event dispatch thread, or the message delivery thread of a JMS provider, for example. You've got to instantiate the listener at a location and time when you can give it all the context it needs to react to the exception in a sensible way.
Nat
A: 

The usual approach is to ignore the issue. Listeners should not throw unchecked exceptions.

A better approach would be to catch and log RuntimeExceptions. These generally indicate a programming error. If a widget on the screen throw an NPE, then there is no reason why the rest of the window should not finish painting. The user can then save their data and restart or otherwise work around the issue. In the case of Errors it generally means that there is a serious situation, such as OutOfMemeory and catching will just result in thrashing. Nobody bothers doing this.

Tom Hawtin - tackline