gpt4 book ai didi

Java 8 收集与减少

转载 作者:搜寻专家 更新时间:2023-10-31 20:01:56 26 4
gpt4 key购买 nike

众所周知,在进行累加时,“reduce”总是返回一个新的不可变对象(immutable对象),而“collect”将对可变对象进行更改。

然而,当我不小心将一个方法引用分配给 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 是一个功能接口(interface),其功能声明如下:

void accept(T t, U u)

你已经给了它一个参数正确的方法引用,但是返回类型错误:

public MutableContainer reduce(long param) {
return new MutableContainer(param);
}

[T参数实际上是调用reduce时的this对象,因为reduce是一个实例方法而不是静态方法。这就是参数正确的原因。] 但是,返回类型是 MutableContainer 而不是 void。所以问题是,为什么编译器会接受它?

直觉上,我认为这是因为方法引用或多或少等同于如下所示的匿名类:

new BiConsumer<MutableContainer,Long>() {
@Override
public void accept(MutableContainer t, Long u) {
t.reduce(u);
}
}

请注意,t.reduce(u) 将返回一个结果。然而,结果被丢弃。由于可以使用结果调用方法并丢弃结果,我认为,推而广之,这就是为什么可以在方法返回结果的地方使用方法引用,对于方法返回 void< 的功能接口(interface)

从法律上讲,我认为原因在 JLS 15.12.2.5 .这部分很难,我没有完全理解,但是在这部分的某个地方它说

If e is an exact method reference expression ... R2 is void.

其中,如果我没看错的话,R2 是功能接口(interface)方法的结果类型。我认为这是允许在需要 void 方法引用的地方使用非 void 方法引用的子句。

(编辑: 正如 Ismail 在评论中指出的那样,JLS 15.13.2 可能是此处的正确子句;它讨论了方法引用与函数类型一致,以及条件之一这是函数类型的结果是void。)

无论如何,这应该可以解释为什么它编译。当然,编译器无法始终判断您何时执行某些会产生错误结果的操作。

关于Java 8 收集与减少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27674126/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com