我正在使用一个类似于以下内容的界面:
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表达式中使用它。
我有办法解决这个限制吗?
答案 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.Accessor
和Accessors.Mutator
。但重要的是,这些接口(现在都是功能接口)可以用作允许在代码中使用Java 8 lambda表达式的策略。