For my specific case I want to use functional composition in a reduction; for example:
BiFunction<ImmutableSet<Integer>, ImmutableSet<Integer>, Sets.SetView<Integer>> f = Sets::intersection;
Function<Sets.SetView<Integer>, ImmutableSet<Integer>> g = Sets.SetView::immutableCopy;
BiFunction<ImmutableSet<Integer>, ImmutableSet<Integer>, ImmutableSet<Integer>> biFunction = f.andThen(g);
ImmutableSet<Integer> intersection = Stream.of(ImmutableSet.of(1, 2, 3), ImmutableSet.of(1, 2), ImmutableSet.of(4))
.reduce(biFunction)
.orElse(ImmutableSet.of());
This has a compilation error:
argument mismatch BiFunction cannot be converted to BinaryOperator
Instead, I need to do:
ImmutableSet<Integer> intersection = Stream.of(ImmutableSet.of(1, 2, 3), ImmutableSet.of(1, 2), ImmutableSet.of(4))
.reduce((a, b) -> Sets.intersection(a, b).immutableCopy())
.orElse(ImmutableSet.of());
However, this loses the point-free style that composition provides.
Why is the Stream API is designed like this? A BinaryOperator is a BiFunction, so wouldn't it make more sense to declare the reduce method's parameter with the supertype?
The reduce operation must take arguments of the same type and return an identical type. If it didn't, there'd be a type mismatch. That's exactly what the
BinaryOperatoris:BinaryOperator<T> extends BiFunction<T,T,T>Instead of using a lambda, you can create your
BiFunction. Then create aBinaryOperator: