In Java, Collectors::teeing is a feature introduced in Java 12 that allows you to collect elements of a stream using two different collectors and then combine the results using a BiFunction.
Syntax:
static <T, R1, R2, R> Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger)
Concept:
downstream1: The first collector for processing input elements.
downstream2: The second collector for processing input elements.
merger: A BiFunction that merges the results of the two collectors.
The teeing collector is useful when you want to process a stream in two different ways simultaneously and combine the results.
Example 1: Calculate the Average and Sum of a Stream
Here’s how you can calculate both the sum and average of a list of integers simultaneously:
package org.kodejava.util.stream;
import java.util.List;
import java.util.stream.Collectors;
public class TeeingExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
var result = numbers.stream()
.collect(Collectors.teeing(
Collectors.summingInt(i -> i), // Collector 1: Sum
Collectors.averagingInt(i -> i), // Collector 2: Average
(sum, avg) -> "Sum: " + sum + ", Avg: " + avg // Merger
));
System.out.println(result); // Output: Sum: 15, Avg: 3.0
}
}
Example 2: Get Statistics (Min and Max) from a Stream
You can create a single step operation to compute the minimum and maximum values of a stream:
package org.kodejava.util.stream;
import java.util.List;
import java.util.stream.Collectors;
public class TeeingStatsExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(3, 5, 7, 2, 8);
var stats = numbers.stream()
.collect(Collectors.teeing(
Collectors.minBy(Integer::compareTo), // Collector 1: Get Min
Collectors.maxBy(Integer::compareTo), // Collector 2: Get Max
(min, max) -> new int[]{min.orElse(-1), max.orElse(-1)} // Merge into an array
));
System.out.println("Min: " + stats[0] + ", Max: " + stats[1]);
// Output: Min: 2, Max: 8
}
}
How It Works:
- Two collectors (
downstream1 and downstream2) collect the stream elements independently. For example, the first collector might compute the sum, while the second computes the average.
- Once the stream has been fully processed, the results from both collectors are passed to the
merger, which applies a transformation or combination of the two results.
Example 3: Concatenate Strings and Count Elements Simultaneously
Here’s how you can process a stream of strings to count the number of elements and also concatenate them into a single string:
package org.kodejava.util.stream;
import java.util.List;
import java.util.stream.Collectors;
public class TeeingStringExample {
public static void main(String[] args) {
List<String> names = List.of("Alice", "Bob", "Charlie");
var result = names.stream()
.collect(Collectors.teeing(
Collectors.joining(", "), // Collector 1: Concatenate strings
Collectors.counting(), // Collector 2: Count elements
(joined, count) -> joined + " (Total: " + count + ")" // Merge
));
System.out.println(result); // Output: Alice, Bob, Charlie (Total: 3)
}
}
Key Points:
- Stream Processing: The stream elements are processed only once but collected using two different collectors.
- Merger Function: The merger combines both results into a final result of your choice.
- Utility:
Collectors::teeing is very useful when you need to perform dual aggregations in one pass over the data.
Now you’re ready to use Collectors::teeing for combining results in your streams!