gpt4 book ai didi

java - 为什么 Stream#reduce 不隐式接受处理父类(super class)型元素的累积函数?

转载 作者:太空狗 更新时间:2023-10-29 23:03:27 25 4
gpt4 key购买 nike

考虑到这些类和累积函数,它们代表了我原始上下文的简化(但重现了相同的问题):

abstract static class Foo {
abstract int getK();
}
static class Bar extends Foo {
int k;
Bar(int k) { this.k = k; }
int getK() { return this.k; }
}

private static Foo combined(Foo a1, Foo a2) {
return new Bar(a1.getK() + a2.getK());
}

我试图通过依赖一个单独的函数 combined 来执行项目的累积(最初是数据索引报告),它直接处理 Foo 类型的元素。

Foo outcome = Stream.of(1,2,3,4,5)
.map(Bar::new)
.reduce((a,b) -> combined(a, b))
.get();

事实证明,此代码会导致编译错误(OpenJDK“1.8.0_92”):“lambda 表达式中的错误返回类型:Foo 无法转换为 Bar”。编译器坚持尝试使用 Bar 作为累加元素来减少流,即使 Foo 作为累加函数的参数及其返回值的通用类型也是如此类型。

我还发现奇怪的是,只要我明确地将流映射到 Foo 流中,我仍然可以采用这种方法:

Foo outcome = Stream.of(1,2,3,4,5)
.<Foo>map(Bar::new)
.reduce((a,b) -> combined(a, b))
.get();

这是 Java 8 泛型类型推断的限制、Stream#reduce 的这种特殊重载的小问题,还是 Java 规范支持的有意行为?我已经阅读了一些关于 SO 的其他问题,其中类型推断“失败”,但这个特殊情况对我来说仍然有点难以理解。

最佳答案

问题是你肯定在创建一个 BinaryOperator<Foo> - 你必须是,因为你要返回 Foo .如果你改变 combined()待申报返回Bar (虽然仍然接受 Foo)那么你会没事的。问题在于返回类型与输入类型相关联 - 它既不能协变也不能逆变,因为它用于输入 输出。

换句话说 - 你期待 reduce((a, b) -> combined(a, b))返回 Optional<Foo> , 正确的?所以这表明您期待 Treduce()调用 Foo - 这意味着它应该在 Stream<Foo> 上运行. Stream<Bar>只有一个参数 reduce采用 BinaryOperator<Bar> 的方法,以及您使用 combined 的 lambda 表达式简单不是 BinaryOperator<Bar> .

另一种方法是向 lambda 表达式添加强制转换:

Foo outcome = Stream.of(1,2,3,4,5)
.map(Bar::new)
.reduce((a,b) -> (Bar)combined(a, b))
.get();

关于java - 为什么 Stream#reduce 不隐式接受处理父类(super class)型元素的累积函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37228875/

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