The Collectors.teeing() is a new feature introduced in Java 12 as part of the Stream API enhancements. It allows two different collectors on a stream and then merges their results using a specified BiFunction.
Let us learn when and how to use the Collectors.teeing() method.
1. Purpose of teeing collector
The Collectors.teeing() method is useful when we want to simultaneously process a stream in two different ways and then combine their results. If not using the teeing() method, we would have processed the stream two times, teeing() allows to process in a single statement.
During stream processing, 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.
Please note that teeing() function helps perform a certain task in a single step. We can surely perform the given task in two steps if we do not use the teeing()
function. It’s just a helper function that helps in reducing the verbosity.
2. Syntax
The syntax is as follows:
downstream1
: The first collector.downstream2
: The second collector.merger
: A BiFunction to merge the results of the two collectors.
/**
* downstream1 - the first downstream collector
* downstream2 - the second downstream collector
* merger - the function which merges two results into the single one
* returns - a Collector which aggregates the results of two supplied collectors.
*/
public static Collector teeing (Collector downstream1,
Collector downstream2,
BiFunction merger);
3. Using Collectors.teeing() to Find Max and Min
In this Collectors.teeing() example, we have a list of employees. We want to find out employees with maximum and minimum salaries in a single step.
The following Java program performs finding max and min operations, then collects both items in a Map.
List<Employee> employeeList = List.of(
new Employee(1, "A", 100),
new Employee(2, "B", 200),
new Employee(3, "C", 300),
new Employee(4, "D", 400));
HashMap<String, Employee> result = employeeList.stream().collect(
Collectors.teeing(
Collectors.maxBy(Comparator.comparing(Employee::getSalary)),
Collectors.minBy(Comparator.comparing(Employee::getSalary)),
(e1, e2) -> {
HashMap<String, Employee> map = new HashMap();
map.put("MAX", e1.get());
map.put("MIN", e2.get());
return map;
}
));
System.out.println(result);
In the above example,
- Collectors.maxBy is the first collector.
- Collectors.minBy is the second collector.
- Merger function produces the HashMap.
Program output.
{
MIN=Employee [id=1, name=A, salary=100.0],
MAX=Employee [id=4, name=D, salary=400.0]
}
4. Using Collectors.teeing() to Filter and Count
In this example, we will use the same set of employees. Here, we will find all employees with a salary greater than 200, and then we will also count the number of such employees.
List<Employee> employeeList = List.of(
new Employee(1, "A", 100),
new Employee(2, "B", 200),
new Employee(3, "C", 300),
new Employee(4, "D", 400));
HashMap<String, Object> result = employeeList.stream().collect(
Collectors.teeing(
Collectors.filtering(e -> e.getSalary() > 200, Collectors.toList()),
Collectors.filtering(e -> e.getSalary() > 200, Collectors.counting()),
(list, count) -> {
HashMap<String, Object> map = new HashMap();
map.put("list", list);
map.put("count", count);
return map;
}
));
System.out.println(result);
Program output.
{
count=2,
list=[Employee [id=3, name=C, salary=300.0], Employee [id=4, name=D, salary=400.0]]
}
5. Using Collectors.teeing() to Average and Sum
Suppose we have a list of numbers and we want to calculate and print both the average and the sum of a list of integers.
List<Integer> numbers = IntStream.rangeClosed(1, 10).boxed().toList();
String result = numbers.stream().collect(
Collectors.teeing(
Collectors.averagingInt(Integer::intValue),
Collectors.summingInt(Integer::intValue),
(average, sum) -> String.format("Average: %.2f, Sum: %d", average, sum)
)
);
System.out.println(result);
6. Conclusion
The above examples of Collectors.teeing() method are very simple and written for basic understanding. We need to use the function very specific to our own needs.
Simply remember that when we need to perform stream operation twice and collect results in two different collectors, consider using teeing() method. It will not always fit in the usecase, but it may be useful when it fits in.
Happy Learning !!
Reference: Java Doc
Comments