[英]Java 8 collect vs reduce
众所周知,当进行累加时,“减少”总是返回一个新的不可变对象,而“收集”将对可变对象进行更改。
但是,当我不小心将一个方法引用分配给reduce方法和collect方法时,它编译时没有任何错误。 为什么?
看下面的代码:
public class Test {
@Test
public void testReduce() {
BiFunction<MutableContainer,Long,MutableContainer> func =
MutableContainer::reduce;
// Why this can compile?
BiConsumer<MutableContainer,Long> consume =
MutableContainer::reduce;
// correct way:
//BiConsumer<MutableContainer,Long> consume =
// MutableContainer::collect;
long param=10;
MutableContainer container = new MutableContainer(0);
consume.accept(container, param);
// here prints "0",incorrect result,
// because here we expect a mutable change instead of returning a immutable value
System.out.println(container.getSum());
MutableContainer newContainer = func.apply(container, param);
System.out.println(newContainer.getSum());
}
}
class MutableContainer {
public MutableContainer(long sum) {
this.sum = sum;
}
public long getSum() {
return sum;
}
public void setSum(long sum) {
this.sum = sum;
}
private long sum;
public MutableContainer reduce(long param) {
return new MutableContainer(param);
}
public void collect(long param){
this.setSum(param);
}
}
基本上,问题可以BiConsumer
为: BiConsumer
是一个函数接口,其函数声明如下:
void accept(T t, U u)
您为它提供了具有正确参数的方法引用,但返回类型错误:
public MutableContainer reduce(long param) {
return new MutableContainer(param);
}
[该T
参数实际上是this
对象时reduce
被调用时,由于reduce
是一个实例方法而不是静态方法。 这就是参数正确的原因。]返回类型为MutableContainer
而不是void
。 所以问题是,编译器为什么接受它?
直觉上,我认为这是因为方法引用或多或少等于一个看起来像这样的匿名类:
new BiConsumer<MutableContainer,Long>() {
@Override
public void accept(MutableContainer t, Long u) {
t.reduce(u);
}
}
请注意, t.reduce(u)
将返回结果。 但是,结果将被丢弃。 由于可以用结果调用方法并丢弃结果,因此,我认为,通过扩展,这就是为什么对于方法返回void
的功能接口,可以使用方法引用(方法返回结果)的原因。
从法律上讲 ,我相信原因是在JLS 15.12.2.5中 。 本节很困难,我还没有完全理解,但是在本节的某处说
如果e是精确的方法引用表达式,则R 2为空。
如果我正确阅读,则R 2是功能接口方法的结果类型。 我认为这是允许在需要void方法引用的地方使用非void方法引用的子句。
( 编辑:正如Ismail在评论中指出的那样, JLS 15.13.2在这里可能是正确的子句;它谈到方法引用与函数类型一致,而其中的条件之一就是函数类型的结果void
。)
无论如何,那应该有望解释它为什么编译 。 当然,编译器不能总是告诉您什么时候做会产生错误结果的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.