SWT listeners are incompatible with Java lambdas

Programming in C# for the last few weeks has really gotten me to pay attention to all of Java’s inadequacies. One of the biggest ones, which C# handles so well, is lambda functions, or closures. Java has been promising to add support for them forever, and it looks like it’s finally going to happen in Java 8. But I’m not exactly watering at the mouth, mostly because the way they have chosen to implement it is going to make adoption by existing libraries a huge pain in the ass. Here’s the problem:

Interfaces that have just one method are called functional interfaces. Lambda expressions can be used anywhere we have a functional interface.

Sure, there are lots of interfaces with just one method, like Runnable, Callable, FileFilter, etc., and all of these will be able to enjoy the nice new syntactic sugar. This:

button.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
        ui.dazzle(e.getModifiers());
    }
});

Becomes this:

button.addActionListener(e -> { ui.dazzle(e.getModifiers()); });
button.addActionListener(e -> { ui.dazzle(e.getModifiers()); });

Pretty nice, huh?

Well, there’s just one problem: you can’t do this if the interface required by the method signature has more than one method defined. In my other life I spend a lot of time writing Eclipse plugins using a pretty nice windowing toolkit called SWT. Most of SWT’s listener interfaces have more than one method defined on them. SelectionListener has two. FocusListener has two. DropTargetListener has five. So any method that takes one of these interfaces can’t join in the syntax sugar party, sorry.

This problem isn’t specific to SWT — all the classes above were basically adapted from analogues in Java’s own AWT. Most libraries declare mostly non-functional interfaces that require you to implement more than one method to use. SWT and other frameworks get around this by providing abstract classes they call Adapters, such as SelectionAdapter. When you don’t want to implement one of the interface’s methods, you just supply an anonymous inner class that extends the adapter, rather than the interface, like so:

button.addSelectionListener(new SelectionAdapter() { 
    public void widgetSelected(SelectionEvent e) { 
        playAnAnnoyingSound();
    }
});

There is absolutely no support in Java 8 for lambdas that use this wide-spread pattern. You won’t be able to use lambdas anywhere you currently do something like this.

I understand that it’s tough to add language features, but people need to be able to use the new features, and use them consistently, for them to be useful. Forcing me to hop back and forth between anonymous inner classes and the nice new lambda syntax is just terrible. I think the attitude I’m supposed to adopt is that whenever I get to use the new syntactical sugar I’m being given a special treat, but I just can’t look at it that way.

As an alternative, the compiler could (this is just off the top of my head) generate an anonymous class for you with the Adapter pattern, allowing you to, in effect, implement only part of an interface as you saw fit. This would dovetail nicely with the new default implementation for interfaces, don’t you think?

If anyone has a tricky way to get around this issue by adding some layers of abstraction, I’m all ears.

One thought on “SWT listeners are incompatible with Java lambdas

Leave a Reply