Java 8 Lambda Expressions - what about multiple methods in nested class

Solution 1:

From JLS 9.8

A functional interface is an interface that has just one abstract method, and thus represents a single function contract.

Lambdas require these functional interfaces so are restricted to their single method. Anonymous interfaces still need to be used for implementing multi-method interfaces.

addMouseListener(new MouseAdapter() {

    @Override
    public void mouseReleased(MouseEvent e) {
       ...
    }

    @Override
    public void mousePressed(MouseEvent e) {
      ...
    }
});

Solution 2:

You can use multi-method interfaces with lambdas by using helper interfaces. This works with such listener interfaces where the implementations of unwanted methods are trivial (i.e. we can just do what MouseAdapter offers too):

// note the absence of mouseClicked…
interface ClickedListener extends MouseListener
{
    @Override
    public default void mouseEntered(MouseEvent e) {}

    @Override
    public default void mouseExited(MouseEvent e) {}

    @Override
    public default void mousePressed(MouseEvent e) {}

    @Override
    public default void mouseReleased(MouseEvent e) {}
}

You need to define such a helper interface only once.

Now you can add a listener for click-events on a Component c like this:

c.addMouseListener((ClickedListener)(e)->System.out.println("Clicked !"));

Solution 3:

The Lambda EG did consider this issue. Many libraries use functional interfaces, even though they were designed years before functional interface became a thing. But it does happen sometimes that a class has multiple abstract methods, and you only want to target one of them with a lambda.

The officially recommended pattern here is to define factory methods:

static MouseListener clickHandler(Consumer<MouseEvent> c) { return ... }

These can be done directly by the APIs themselves (these could be static methods inside of MouseListener) or could be external helper methods in some other library should the maintainers choose not to offer this convenience. Because the set of situations where this was needed is small, and the workaround is so simple, it did not seem compelling to extend the language further to rescue this corner case.

A similar trick was employed for ThreadLocal; see the new static factory method withInitial(Supplier<S>).

(By the way, when this issue comes up, the example is almost always MouseListener, which is encouraging as it suggests the set of classes which would like to be lambda friendly, but aren't, is actually pretty small.)

Solution 4:

A Java ActionListener must implement just one single method (actionPerformed(ActionEvent e)). This fits nicely into the Java 8 function so Java 8 provides a simple lambda to implement an ActionListener.

The MouseAdapter requires at least two methods so does not fit as a function.