everybody.
In the Oracle tutorial about Reduction (https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html) we have the example of how to use the Stream.collect() method. The task is to find the average of values in the stream. In the example there is the auxillary class Averager:
class Averager implements IntConsumer
{
private int total = 0;
private int count = 0;
public double average() {
return count > 0 ? ((double) total)/count : 0;
}
public void accept(int i) { total += i; count++; }
public void combine(Averager other) {
total += other.total;
count += other.count;
}
}
and then we have something like that:
Averager averageCollect = roster.stream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.map(Person::getAge)
.collect(Averager::new, Averager::accept, Averager::combine).
So we are recommended to use three method references of that auxillary class. Since the Stream.collect signature is:
collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
, where BiConsumer - the functional interface wich has functional method accept(Object, Object).
The question is how can we use Avereager::accept (signature void accept(int i) - one parameter, returns no value) in place of second parameter of collect() - which is the function, that returns no value but accepts two parameters. If we dig into all these library calls we can find some transformation of input lambdas which lead to appropriate call of accept(a, b) - with two parameters, but how the compiler initially recognizes it is correct?
We can rewrite the collect() invocation like that:
...collect(() -> new Averager(), (a, i) -> a.accept(i), Averager::combine),
using lambdas instead of methods references, but still I don't catch how the second lambda can have one parameter, while it should be two.
Thank you in advance.
I think the confusion lies in the fact that you can do the following:
Averager avg = new Averager();
BiConsumer<Averager, Integer> consumer = Averager::accept;
consumer.accept(avg, 17);
That is although Averager::accept
has a signature that says that it accepts one parameter (int i
) it can be regarded as a BiConsumer<Averager, Integer>
that accepts two arguments: A callee (a "this
") and an argument (int i
).
Further reading: The Java™ Tutorials: Method References