有没有办法将现有界面变成功能界面?

时间:2014-04-25 04:51:23

标签: java lambda java-8 functional-interface

我正在使用一个类似于以下内容的界面:

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

我目前正在使用匿名类来实现该接口,但我并不关心这两种方法中的一种。有点像这样:

someObject.addListener(new ObjectListener() {

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

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

现在,我已经在Java 8中使用了新的lambda表达式,无论我在哪里,我都希望在这种情况下使用增加的简单性。毕竟,我只实现了其中一种方法,但由于界面中有两种方法,我无法在lambda表达式中使用它。

我有办法解决这个限制吗?

2 个答案:

答案 0 :(得分:9)

为了重用lambda表达式中不是函数接口的现有接口,还必须使用新的Java8特性,默认方法。

在这种情况下,如果您想使用lambda表达式代替匿名类,则必须执行以下操作。

首先,您需要将ObjectListener重新定义为新接口:

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

我们只是简单地将一个空的默认实现添加到我们不关心的方法中,这使得objectAdded()方法成为界面中唯一的抽象方法。

然后你可以使用new类型代替任何ObjectListener,并且因为在新接口中只有一个没有实现的方法,你可以在lambda表达式中使用它,如下所示:

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

请注意,如果您想在addListener()方法中直接使用此新类型,首先需要将lambda表达式转换为新定义的类型,如下所示:

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

答案 1 :(得分:0)

重构不是单个抽象方法(SAM)接口的现有接口以便与Java 8 lambda表达式一起使用的替代方法是将方法分离为它们自己的类型。如果界面中的大多数方法都适合与lambdas一起使用,这是最合适的。

例如,考虑一个接口,该接口允许按字段名称以编程方式访问数据模型对象。界面包含一个用于读取字段的方法和另一个用于改变字段的方法:

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

似乎可能,甚至可能,这两种方法都可以与lambdas一起使用,以获得更好的表现力和简单性。要实现这一点,可以通过这种方式重构接口(仅作为示例;有几种方法可以实现此目的):

class Accessors {

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

    interface Accessor {
         Object acc(String fieldName);
    }

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

提供对数据模型对象的读写访问权限的类现在需要同时实现Accessors.AccessorAccessors.Mutator。但重要的是,这些接口(现在都是功能接口)可以用作允许在代码中使用Java 8 lambda表达式的策略。