Mastering Collectors.teeing() in Java Streams (With Examples)

Java 12 introduced Collectors.teeing(), a powerful feature in the Stream API, allowing us to combine two separate collectors and merge their results into a single output.

Instead of running two separate stream operations, teeing() processes the data in one pass, improving performance and readability.

🛠️ Understanding Collectors.teeing()

🔹 Syntax

Collectors.teeing(
Collector<T, A, R1> downstream1, // First collector
Collector<T, A, R2> downstream2, // Second collector
BiFunction<R1, R2, R> merger // Merging function
)
  • downstream1 → First collector operation.
  • downstream2 → Second collector operation.
  • merger → Combines both collected results into the final output.

💡 Why Use Collectors.teeing()?

Avoids multiple stream traversals (better performance).

✅ Use it for summarizing, grouping, or partitioning data in a single .collect() operation.
Combines different results in a single operation.
Improves readability compared to separate stream calls.

Happy learning :)

📌 Example 1: Calculate Sum & Average Together

Problem: Given a list of numbers, calculate both sum and average in one pass using teeing().

import java.util.List;
import java.util.stream.Collectors;

public class TeeingExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(10, 20, 30, 40, 50);

var result = numbers.stream()
.collect(Collectors.teeing(
Collectors.summingInt(Integer::intValue), // Collector 1: Sum
Collectors.averagingDouble(Integer::doubleValue), // Collector 2: Average
(sum, avg) -> "Sum = " + sum + ", Average = " + avg // Merge results
));

System.out.println(result);
}
}
//-------OUTPUT---//
Sum = 150, Average = 30.0

✨ Key Benefit: This avoids separate .sum() and .average() calculations, making the code more efficient.

📌 Example 2: Find Min & Max Together

Problem: Given a list of numbers, find both minimum and maximum values in a single operation.

import java.util.List;
import java.util.stream.Collectors;

public class TeeingMinMax {
public static void main(String[] args) {
List<Integer> numbers = List.of(5, 10, 2, 8, 20, 3);

var minMax = numbers.stream()
.collect(Collectors.teeing(
Collectors.minBy(Integer::compareTo), // Collector 1: Min
Collectors.maxBy(Integer::compareTo), // Collector 2: Max
(min, max) -> "Min = " + min.get() + ", Max = " + max.get() // Merge
));

System.out.println(minMax);
}
}
//---OUTPUT---//
Min = 2, Max = 20

✨ Key Benefit: Instead of using .min() and .max() separately, teeing() combines them efficiently in one pass.

📌 Example 3: Count Even & Odd Numbers in a List

Problem: Count how many numbers are even and odd in a list.

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TeeingEvenOdd {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Map<String, Long> result = numbers.stream()
.collect(Collectors.teeing(
Collectors.filtering(n -> n % 2 == 0, Collectors.counting()), // Count evens
Collectors.filtering(n -> n % 2 != 0, Collectors.counting()), // Count odds
(evenCount, oddCount) -> Map.of("Even Count", evenCount, "Odd Count", oddCount)
));

System.out.println(result);
}
}
//----OUTPUT--//
{Even Count=5, Odd Count=5}

✨ Key Benefit: Instead of two separate filter operations, we use teeing() to count both even and odd numbers in one pass.

🚀 Performance Benefits of Collectors.teeing()

🔹 Without teeing() (Multiple Stream Traversals)

long evenCount = numbers.stream().filter(n -> n % 2 == 0).count();
long oddCount = numbers.stream().filter(n -> n % 2 != 0).count();

🔴 Two separate .stream() calls → Extra computation cost.

🔹 With teeing() (Single Stream Traversal)

numbers.stream().collect(Collectors.teeing(...));

Only one .stream() call → Faster execution.

📌 When to Use Collectors.teeing()?

📌 Limitations of Collectors.teeing()

❌ Available only in Java 12+ (not in Java 8 or 11).
Only works with two collectors (not three or more).
❌ Less useful if both collectors need post-processing.

Happy learning :)

--

--

Responses (1)