Return to site

🧩⚡ COLLECTORS.TEEING(): TWO AGGREGATIONS, ONE STREAM PASS

· java

🔸 TLDR

▪️ Need two aggregations? teeing() does it in one collect with a clean immutable merge.

Section image

🔸 THE PROBLEM

Ever needed two aggregations (ex: count + sum) on the same stream?

The “classic” approach often streams the data twice — simple, but not always ideal.

🔸 CODE: OLD VS MODERN

// ✕ Java 8: two passes
long count = items.stream().count();
double sum = items.stream()
 .mapToDouble(Item::price)
 .sum();
var result = new Stats(count, sum);

// ✓ Java 12+: one pass with teeing()
var result = items.stream().collect(
 Collectors.teeing(
 Collectors.counting(),
 Collectors.summingDouble(Item::price),
 Stats::new
 )
);

🔸 SEE A PROBLEM WITH THIS CODE? LET US KNOW 👀

Hint: there’s a subtle one depending on what items is… 😉

🔸 WHY THE MODERN WAY WINS

▪️ ⚡ Single pass: stream once, aggregate twice

▪️ 🧩 Composable: mix any 2 collectors (min/max, summary stats, grouping, etc.)

▪️ 🔒 Immutable result: merge straight into a record / value object

🔸 HOW IT WORKS (IN 1 SENTENCE)

Collectors.teeing() routes each element to two downstream collectors, then merges both results using your merger function (Stats::new here).

🔸 TAKEAWAYS

▪️ Prefer teeing() when you want two results from one stream without mutable accumulators

▪️ Great fit for Stats/DTO/record building

▪️ Still keep readability in mind: for tiny lists, two passes can be totally fine ✅

#Java #Java12 #Streams #Collectors #FunctionalProgramming #CleanCode

#Performance #BackendDevelopment #JVM

Go further with Java certification:

Java👇

Spring👇

SpringBook👇

JavaBook👇