https://blog.frankel.ch/teeing-java-api/

Last week, I described a use-case for a custom Stream Collector. I received a intriguing comment on Twitter:
Interesting article. For completness' sake this specific problem could also be solved using the standard teeing collector— Miguel Martins (@Miguucm) May 3, 2021
Hats off to you, Miguel! Your comment revealed a method I didn’t know!
So I decided to investigate what is the teeing() method about.
Returns a Collector that is a composite of two downstream collectors. Every element passed to the resulting collector is processed by both downstream collectors, then their results are merged using the specified merge function into the final result. The resulting collector functions do the following: supplier: creates a result container that contains result containers obtained by calling each collector’s supplieraccumulator: calls each collector’s accumulator with its result container and the input elementcombiner: calls each collector’s combiner with two result containersfinisher: calls each collector’s finisher with its result container, then calls the supplied merger and returns its result.
We can indeed replace our custom Collector with two simple Collector implementations, one aggregating price rows and the other summing the cart’s price.
Let’s look at the final code and explain it line by line.
public PriceAndRows getPriceAndRows(Cart cart) {
return cart.getProducts()
.entrySet()
.stream()
.map(CartRow::new)
.collect(Collectors.teeing(
Collectors.reducing(BigDecimal.ZERO, CartRow::getRowPrice, BigDecimal::add),
Collectors.toList(),
PriceAndRows::new
));
}
Entry
teeing()
reducing()
CartRow