9

I am using an interface that looks something along the lines of this:

public interface ObjectListener {
    public void objectAdded(Object o);
    public void objectRemoved(Object o);
}

And I am currently using an anonymous class to implement the interface, but I don't care about one of the two methods. Something along the lines of this:

someObject.addListener(new ObjectListener() {

    @Override
    public void objectAdded(Object o) {
        doSomething(o);
    }

    @Override
    public void objectRemoved(Object o) {}
});

Now, I've been using the new lambda expressions in Java 8 wherever I'm able, and I would like to use the added simplicity in a situation like this. After all, I'm only implementing one of the methods, but since there are two methods in the interface, I can't use it in a lambda expression.

Is there a way for me to get around this restriction?

4

2 回答 2

9

In order to reuse an existing interface that is not a functional interface in a lambda expression, you must also use the new Java8 feature, default methods.

In this case, if you wanted to use a lambda expression in place of the anonymous class, you would have to do the following.

First, you need to redefine the ObjectListener as a new interface:

public interface ObjectAddedListener extends ObjectListener {
    @Override
    default public void objectRemoved(Object o) {}
}

We just simply add an empty default implementation to the method that we don't care about, which leaves the objectAdded() method as the sole abstract method in the interface.

Then you can use the new type in place of any ObjectListener, and since there is only one method without an implementation in the new interface, you can use it in lambda expressions, like so:

ObjectAddedListener listener = o -> doSomething(o);
someObject.addListener(listener);

Note that if you wanted to use this new type directly in the addListener() method you would first need to cast the lambda expression as the newly defined type like so:

someObject.addListener((ObjectAddedListener) o -> doSomething(o));
于 2014-04-25T04:51:22.750 回答
0

An alternative for refactoring an existing interface that is not a single abstract method (SAM) interface to enable use with Java 8 lambda expressions is to separate methods into their own types. This is most appropriate if most of the methods in the interface are amenable to use with lambdas.

For example, consider an interface that enables the programmatic access to data model objects by field name. The interface contains a method for reading the field and another for mutating the field:

interface Accessible {
    Object acc(String fieldName);
    void mut(String fieldName, Object val);
}

It seems possible, even likely, that both these methods could be used with lambdas for better expressiveness and simplicity. To achieve this, the interface could be refactored this way (just as an example; there are a few ways to do this):

class Accessors {

    private Accessors() { throw new AssertionError(); }

    interface Accessor {
         Object acc(String fieldName);
    }

    interface Mutator {
         void mut(String fieldName, Object val);
    }
}

Classes that provide both read and write access to data model objects would now need to implement both Accessors.Accessor and Accessors.Mutator. Importantly, though, these interfaces (now both functional interfaces) can be used as strategies that enable the use of Java 8 lambda expressions in your code.

于 2015-04-04T21:56:58.720 回答