How do I use Collectors::teeing in Streams?

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:

  1. downstream1: The first collector for processing input elements.
  2. downstream2: The second collector for processing input elements.
  3. 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:

  1. Stream Processing: The stream elements are processed only once but collected using two different collectors.
  2. Merger Function: The merger combines both results into a final result of your choice.
  3. 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!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.