- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
考虑到这些类和累积函数,它们代表了我原始上下文的简化(但重现了相同的问题):
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>
, 正确的?所以这表明您期待 T
的 reduce()
调用 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/
我是一名优秀的程序员,十分优秀!