假设我有以下功能界面:
public interface TemperatureObserver {
void react(BigDecimal t);
}
然后在另一个类中已经填充ArrayList
类型为TemperatureObserver
的对象。
假设temp
是BigDecimal
,我可以使用以下方法在循环中调用react
:
observers.forEach(item -> item.react(temp));
我的问题:我可以为上面的代码使用方法参考吗?
以下不起作用:
observers.forEach(TemperatureObserver::react);
错误消息告诉我
forEach
中的Arraylist observers
不适用于TemperatureObserver::react
TemperatureObserver
未定义方法react(TemperatureObserver)
很公平,因为forEach
期望作为参数Consumer<? super TemperatureObserver>
,我的界面虽然功能正常但不符合Consumer
,因为react
的参数不同(在我的情况下是BigDecimal
)。
这样可以解决,还是lambda没有相应的方法参考?
答案 0 :(得分:20)
当流中有单个值时,可以使用三种方法引用:
流式传输对象的无参数方法。
class Observer {
public void act() {
// code here
}
}
observers.forEach(Observer::act);
observers.forEach(obs -> obs.act()); // equivalent lambda
流对象成为方法的this
对象。
以流对象作为参数的静态方法。
class Other {
public static void act(Observer o) {
// code here
}
}
observers.forEach(Other::act);
observers.forEach(obs -> Other.act(obs)); // equivalent lambda
以流对象作为参数的非静态方法。
class Other {
void act(Observer o);
}
Other other = new Other();
observers.forEach(other::act);
observers.forEach(obs -> other.act(obs)); // equivalent lambda
还有一个构造函数引用,但这与此问题并不相关。
由于您有一个外部值temp
,并且您想使用方法引用,您可以执行第三个选项:
class Temp {
private final BigDecimal temp;
public Temp(BigDecimal temp) {
this.temp = temp;
}
public void apply(TemperatureObserver observer) {
observer.react(this.temp);
}
}
Temp tempObj = new Temp(temp);
observers.forEach(tempObj::apply);
答案 1 :(得分:9)
看看Method References section in the Java Tutorial。它说:
有四种方法参考:
对静态方法的引用:
ContainingClass::staticMethodName
引用特定对象的实例方法:
containingObject::instanceMethodName
引用特定类型的任意对象的实例方法:
ContainingType::methodName
对构造函数的引用:
ClassName::new
在那里它解释了ie TemperatureObserver::react
将是第三种类型的方法引用:对特定类型的任意对象的实例方法的引用。在调用Stream.forEach
方法的上下文中,该方法引用将等效于以下lambda表达式:
(TemperatureObserver item) -> item.react()
或者只是:
item -> item.react()
与您的void TemperatureObserver.react(BigDecimal t)
方法签名不符。
正如您已经怀疑的那样,有些情况下您无法找到lambda的等效方法引用。 Lambda更灵活,虽然恕我直言有时它们比方法参考更不可读(但这是一个品味的问题,许多人认为反过来)。
仍然使用方法引用的方法是使用辅助方法:
public static <T, U> Consumer<? super T> consumingParam(
BiConsumer<? super T, ? super U> biConsumer,
U param) {
return t -> biConsumer.accept(t, param);
}
您可以使用以下内容:
observers.forEach(consumingParam(TemperatureObserver::react, temp));
但老实说,我更喜欢使用lambda。
答案 2 :(得分:6)
它不起作用,因为你迭代处理程序而不是参数。
例如,此代码有效:
ArrayList<BigDecimal> temps = new ArrayList<>();
TemperatureObserver observer = new TemperatureObserverImpl();
temps.forEach(observer::react);