the documentation describes Collectors # mapping as:
Adapts a Collector element that accepts type U elements to one receive element of type T , applying a matching function to each input element before accumulating.
The mapping() collectors are most useful when used in multilevel reduction, for example, below groupingBy or partitioningBy .
which means that you can create any possible Collector as you can.
import static java.util.stream.Collectors.*; Map<String, Long> total_of_C_per_A(Stream<Ia> streamOfA) { return streamOfA.collect(groupingBy( Ia::getName, mapping( Ia::getBs, mapping( it -> it.flatMap(Ib::getCs), // reduce() does boxing & unboxing ---v mapping(Stream::count, reducing(0L,Long::sum)) ) ) )); }
OR , using # summingLong instead of the collector .
Map<String, Long> total_of_C_per_A(Stream<Ia> streamOfA) { return streamOfA.collect(groupingBy( Ia::getName, mapping( Ia::getBs, mapping( it -> it.flatMap(Ib::getCs), // summingLong() does boxing ---v mapping(Stream::count, summingLong(Long::longValue)) // Long::longValue does unboxing operation ---^ ) ) )); }
thanks for @Holger pointing out the potential problem of the above code, instead you can just use summingLong(Stream::count) . in this approach, there is no need to box Stream#count , which returns long to long . and Long::longValue unboxing a long to long .
Map<String, Long> total_of_C_per_A(Stream<Ia> streamOfA) { return streamOfA.collect(groupingBy( Ia::getName, mapping( Ia::getBs,