Java Exception handling within “events”

eventsexceptionjava

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?

Best Answer

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.