Учитывая эти классы и функцию накопления, которые представляют собой упрощение моего исходного контекста (все же воспроизводя ту же проблему):
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" ): "Плохой тип возврата в выражении лямбда: Foo не может быть преобразован в Bar". Компилятор настаивает на попытке уменьшить поток, используя Bar
как накопительный элемент, даже если существует Foo
как общий тип для обоих аргументов кумулятивной функции и ее возвращаемого типа.
Я также считаю своеобразным, что я все еще могу использовать этот подход, пока я явно сопоставляю поток в поток Foo
s:
Foo outcome = Stream.of(1,2,3,4,5)
.<Foo>map(Bar::new)
.reduce((a,b) -> combined(a, b))
.get();
Является ли это ограничением вывода типа generic типа Java 8, небольшой проблемой с этой конкретной перегрузкой Stream#reduce
или преднамеренным поведением, которое поддерживается спецификацией Java? Я прочитал еще несколько вопросов о SO, где вывод типа "провалился", но этот конкретный случай по-прежнему мне трудно понять.