Enforce strict type safety with generics

Create a simple event dispatcher using generics

Event-driven design has been around for quite some time. Within Java, both AWT (Abstract Window Toolkit) and Swing are based on an event model. Java provides the classes EventQueue, AWTEvent, AWTEventMultiCaster, and EventListener in the java.awt package. However, because I wanted to use events generally and not merely in the context of graphical UI operations, I ended up writing a simple dispatcher of my own. In this article, I present the pre-generics version of this dispatcher and show how the introduction of generics improved the mechanism's usability.

I wanted an all-purpose dispatcher that would maintain listener lists for any type of event. The Swing tradition of writing many little methods to the pattern addXxxxListener(XxxxListener l); troubled me. To register a listener for an event, I wanted, as a client of my API, to be able to write this:

ThingChangedListener listener = new ThingChangedListener() { /* implement stuff here */ };
dispatcher.register(ThingChangedEvent.class, listener);

This way, the code interested in the event is completely decoupled from the code that generates the event. In the example above, I want to know when "ThingChanged" happens, but I don't care who makes it happen.

Similarly, to fire an event, I wanted to write this:

dispatcher.fire(new ThingChangedEvent());

Now I present the implementation of Dispatcher—first, the pre-generics version, then the generics version. It will be satisfying to observe that client code (such as the two examples above) will remain unaffected by the migration.

In the bad old days ...

Dispatcher used to look like this:

class Dispatcher {
    Map map;
    void register(Class eventClass, Object listener) { ... }
    void fire(Event event) { ... }

Notice that the register() method takes an Object as the second parameter. In other words, it knows nothing about the listener type. Dispatcher gets away with this because it expects Event objects to know how to dispatch themselves. Exactly how events dispatch themselves will become clearer soon.

The register() method adds its listener parameter to a list stored in a map keyed by the eventClass parameter, as follows:

void register(Class type, Object listener) {
    List list = (List)map.get(type);
    if (list == null) {
       list = new ArrayList();
       map.put(type, list);

The fire() method iterates through the list of registered listeners and asks Event to handle each listener by calling its dispatchTo() method. This way, Dispatcher and the listener types are completely decoupled; Dispatcher requires no knowledge about the listener interface. fire() looks like this:

void fire(Event event) {
    List list = (List)map.get(event.getClass());
    if (list == null) {
    for (Iterator i = list.iterator(); i.hasNext();) {

Here is the Event interface:

interface Event {
    void dispatchTo(Object listener);

This interface is somewhat inspired by java.awt.ActiveEvent. It differs in that the dispatch method takes a parameter, the listener to which Event should dispatch itself. This parameter's type is Object; in other words, it lacks type information. An Event implementation casts its listener parameter to the desired type and then calls whatever method it wants on its listener. Here's an example:

class ThingChangedEvent implements Event {
    public void dispatchTo(Object listener) {
       ThingChangedListener tcl = (ThingChangedListener)listener;

The example assumes that the ThingChangedListener interface has an updateThing() method. Only ThingChangedEvent knows that its listeners are of type ThingChangedListener—the Dispatcher has no clue what's going on and merely delegates actual dispatching to Event itself.

What's the problem with this arrangement?

The problem with this implementation is the existence of a cast. If I call dispatcher.register(), but mistakenly pass the wrong kind of listener, the dispatcher won't catch the error and will happily pass my wrongly-typed listener the next time an event of the appropriate type is fired.

In other words, there is a constraint over the types of parameters passed to dispatcher.register(), but without generics, I have no way to express that and must wait for a runtime ClassCastException before I realize my mistake. The compiler cannot prevent me from writing code like this:

dispatcher.register(ThingChangedEvent.class, mySelectionListener);

Swing components avoid this problem by enforcing type safety, using a separate method for each listener type: addThingEventListener(ThingEventListener listener). In Swing's case, the event type is embedded in the method name; in my Dispatcher, the event type is unconstrained, but at the cost of type safety. I dislike the Swing approach because it requires writing another method for every possible listener type.

Now, with generics

Here's the Event interface:

interface Event<L> {
    void dispatchTo(L listener);

Now, my Event subclasses no longer must cast to the expected listener type; it's passed to them directly. Here's the new and improved ThingChangedEvent:

class ThingChangedEvent implements Event<ThingChangedListener> {
    public void dispatchTo(ThingChangedListener tcl) {

I have eliminated a cast and a line of code!

Now that my Event implementation can specify what kind of listener it can dispatch to, my Dispatcher class can use this information. Here is the outline of the new Dispatcher:

class Dispatcher {
    Map<Class, List<? extends Object>> map;
    public <L> void register(Class<? extends Event<L>> type, L listener) { ... }
    public <L> void fire(Event<L> event) { ... }

The register() method signature looks pretty mean. Let's attack the first parameter type, Class<? extends Event<L>>. In the old days, you could write Class someClass to specify any class whatsoever. With generics, Class<String>, for example, specifies String.class and nothing else. Class<? extends Collection> specifies any implementation of Collection. So, Class<? extends Event<L>> specifies any implementation of Event<L>. We must mention <L> to enforce the constraint that the second parameter be an instance of L.

In short, the register() method says that the first parameter is an event class that dispatches itself to L instances, and the second parameter is an instance of L.

The mysterious <L> at the signature's beginning is necessary, because L is a type parameter of the method, not the class.

I agree the syntax is ugly and will possibly create a barrier to learning Java, but the whole generics-are-evil question is well debated elsewhere. I merely hope to show how generics can be used to improve type safety. But on a positive note, as previously mentioned, the ugliness is only in the Dispatcher class; clients calling Dispatcher don't change.

Here's the implementation of register():

public <L> void register(Class<? extends Event<L>> type, L listener) {
    List<L> list = (List<L>)map.get(type);
    if (list == null) {
       list = new ArrayList<L>();
       map.put(type, list);

And here's the implementation of fire():

public <L> void fire(Event<L> event) {
    List<L> list = (List<L>)map.get(event.getClass());
    if (list == null) {
    for (L listener : list) {

The implementations have hardly changed (apart from the convenient new for loop in fire()). The significant difference is in the interface, which now imposes the correct relationship on its method parameter types, which would have proved impossible with mere autocasting. To autocast, you must specify the type, but here we don't care about the type, we only care about the relationship among the types.

Parallel migration in the Collections API

The Java Collections API has undergone a similar migration. In J2SE 1.4, java.util.Collections declared the following method:

public static void sort(List list, Comparator c) { ... }

Here is the new incarnation of sort in Java 5 (Note: With the latest version of Java, Sun has changed its naming and numbering schemes. J2SE is now referred to as simply Java and the versions numbers no longer appear with a "1."; i.e., what would have been J2SE 1.5 is now Java 5.):

public static <T> void sort(List<T> list, Comparator<? super T> c) { ... }

The new method signature guarantees that the provided Comparator will be type-compatible with the given list. The signature says that the things that go in the list must be a subclass of the things that can be sorted by the Comparator. Additionally, Comparator<T> implementations, like Event<L> implementations, no longer need to cast their arguments to the correct types.


The Dispatcher presented here is for simple event-dispatching tasks. Dispatcher could be improved in many ways. Requests could be queued to prevent simultaneous dispatching. It could be made thread-safe. It could be adapted to work as a singleton if desired. It needs an unregister() method so that objects no longer interested in receiving events won't receive them and objects no longer used can be garbage collected.

This article showed how migrating Dispatcher to be generics-aware changed the Dispatcher class and Event interface, but left the existing calling code unchanged. However, some dangerous code, which compiles up to J2SE 1.4 but generates runtime errors if used, no longer compiles in Java 5; therefore some errors that could have led to nasty bugs simply cannot happen in the new Java.

When using human languages, it is easier to understand correct sentences than produce them. With generics, the people who need to produce correct sentences are API developers. Sorry, your lives may have become more difficult with generics. However, most developers use APIs but do not develop them—hence they may need to understand interfaces that use generics, but not necessarily produce such interfaces. Congratulations, your productivity may well improve with generics, with no extra effort on your part!

Conan Dalton is a freelance software writer based in Paris, France. He has been a Java enthusiast ever since Java appeared. He is also interested in design patterns (who isn't ...) and extreme programming.

Learn more about this topic