1

I am trying to use reduce methods on a stream of Integer to get sum of all values. but getting syntax error and not able to figure out the error.

List<Integer> ee = new ArrayList<Integer>();
Function<? super Integer, ? extends Integer> f3 = x -> x / 2;
BinaryOperator<? extends Integer> accumulator = (x, y) -> x + y;
ee.stream().map(f3).reduce(new Integer(0), accumulator);

It gives error :

The method reduce(capture#2-of ? extends Integer, BinaryOperator<capture#2-of ? extends Integer>) in the type Stream<capture#2-of ? extends Integer> is not applicable for the arguments (Integer, BinaryOperator<capture#7-of ? extends Integer>)
Naman
  • 27,789
  • 26
  • 218
  • 353
javaGroup456
  • 313
  • 1
  • 6
  • 21

1 Answers1

7

The problem is with all the bounds you've got there. While it would take me a while to work out (and then explain) exactly what the compiler thinks is going on, it's much simpler if you just change everything to use the concrete type... after all, it's not like this is really a stream of "things that extend integer, but we're not sure what". They're just integers. This code compiles fine, and is also much simpler to understand.

Function<Integer, Integer> f3 = x -> x / 2;
BinaryOperator<Integer> accumulator = (x, y) -> x + y;
int result = ee.stream().map(f3).reduce(Integer.valueOf(0), accumulator);

As noted in comments, autoboxing and the use of a method reference can simplify the last line significantly (and remove the need for the accumulator variable):

int result = ee.stream().map(f3).reduce(0, Integer::sum);

The first snippet retains more of the structure of the question so that it's easier to adapt for other accumulator functions.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • The declaration of `reduce` as`T reduce(T identity, BinaryOperator accumulator)` must be causing it to fail for the inference of the type when `new Integer(0)` is not something that defines `? extends Integer` I would guess. – Naman Nov 12 '19 at 08:03
  • 1
    @Naman: Something like that, yes. Given that the code that compiles is also easier to read, I'm not going to peek behind the curtain too much :) – Jon Skeet Nov 12 '19 at 08:21
  • 2
    It’s actually very simple. A declaration like `BinaryOperator extends Integer> accumulator` specifies that the input type is *unknown*. All we know, is that it is some subtype of `Integer`, but we don’t know which, which makes this function entirely unusable. The other function follows the [PECS rule](https://stackoverflow.com/q/2723397/2711488) which is fine, but the compiler needs a little help like `.map(f3)`. By the way, there’s no need for manual boxing, `reduce(0, accumulator)` or just `reduce(0, Integer::sum)` would do. – Holger Nov 12 '19 at 09:21
  • @Holger: I originally used 0 instead of `Integer.valueOf(0)`, but I wanted to keep it closer to the original code, without the deprecation warning. – Jon Skeet Nov 12 '19 at 09:45