Java Teeing Collector

Introduction

Java 12 introduced a new collector called the Teeing Collector, which is part of the java.util.stream.Collectors utility class. The Teeing Collector allows you to perform two different collection operations on a stream and then combine the results into a final value. It is especially useful when you want to perform multiple operations on the same stream and combine their results into a single object or value.

Key Points:

  • Dual Collection: The Teeing Collector allows you to perform two different downstream operations on the same stream.
  • Result Combination: Combines the results of two downstream collectors into a final result using a BiFunction.
  • Efficiency: Executes the two operations in a single pass over the data, making it efficient.

Using the Teeing Collector

The Teeing Collector is created using the Collectors.teeing() method. This method takes three arguments:

  1. Downstream Collector 1: The first collector operation to be performed on the stream.
  2. Downstream Collector 2: The second collector operation to be performed on the stream.
  3. Merger Function: A BiFunction that combines the results of the two collectors into a final result.

Syntax

Collectors.teeing(Collector<T, A, R1> downstream1, Collector<T, A, R2> downstream2, BiFunction<R1, R2, R> merger) 
  • downstream1: The first downstream collector operation.
  • downstream2: The second downstream collector operation.
  • merger: A BiFunction that combines the results of the two collectors into a final result.

Example: Using the Teeing Collector

Let’s use the Teeing Collector to calculate the average and sum of a list of integers.

Example: Calculate the Sum and Average

import java.util.List; import java.util.stream.Collectors; public class TeeingCollectorExample { public static void main(String[] args) { List<Integer> numbers = List.of(10, 20, 30, 40, 50); // Use the Teeing Collector to calculate sum and average Result result = numbers.stream() .collect(Collectors.teeing( Collectors.summingInt(Integer::intValue), // Downstream 1: Calculate sum Collectors.averagingDouble(Integer::doubleValue), // Downstream 2: Calculate average Result::new // Merger: Combine results into a Result object )); // Print the results System.out.println("Sum: " + result.sum); System.out.println("Average: " + result.average); } // Result class to hold the sum and average static class Result { final int sum; final double average; public Result(int sum, double average) { this.sum = sum; this.average = average; } } } 

Output:

Sum: 150 Average: 30.0 

Explanation:

  • Downstream 1: Uses Collectors.summingInt() to calculate the sum of the integers.
  • Downstream 2: Uses Collectors.averagingDouble() to calculate the average of the integers.
  • Merger Function: Combines the results of the two downstream operations into a Result object containing both the sum and the average.

Real-World Example: Collecting and Combining Data

Suppose you have a list of transactions, and you want to calculate both the total amount and the number of transactions. The Teeing Collector can help you achieve this in a single pass over the data.

Example: Transactions Analysis

import java.util.List; import java.util.stream.Collectors; public class TransactionsExample { public static void main(String[] args) { List<Transaction> transactions = List.of( new Transaction("Food", 150.0), new Transaction("Entertainment", 200.0), new Transaction("Utilities", 300.0), new Transaction("Groceries", 250.0) ); // Use the Teeing Collector to calculate total amount and count TransactionSummary summary = transactions.stream() .collect(Collectors.teeing( Collectors.summingDouble(Transaction::getAmount), // Downstream 1: Calculate total amount Collectors.counting(), // Downstream 2: Count transactions TransactionSummary::new // Merger: Combine results into a TransactionSummary object )); // Print the results System.out.println("Total Amount: " + summary.totalAmount); System.out.println("Transaction Count: " + summary.transactionCount); } // Transaction class representing a transaction static class Transaction { private final String category; private final double amount; public Transaction(String category, double amount) { this.category = category; this.amount = amount; } public double getAmount() { return amount; } } // TransactionSummary class to hold the total amount and transaction count static class TransactionSummary { final double totalAmount; final long transactionCount; public TransactionSummary(double totalAmount, long transactionCount) { this.totalAmount = totalAmount; this.transactionCount = transactionCount; } } } 

Output:

Total Amount: 900.0 Transaction Count: 4 

Explanation:

  • Downstream 1: Uses Collectors.summingDouble() to calculate the total amount of all transactions.
  • Downstream 2: Uses Collectors.counting() to count the number of transactions.
  • Merger Function: Combines the results into a TransactionSummary object containing both the total amount and the transaction count.

Benefits of the Teeing Collector

  • Efficiency: The Teeing Collector processes the stream in a single pass, reducing the need for multiple traversals.
  • Convenience: Simplifies code by combining multiple operations into one.
  • Flexibility: Allows developers to define custom logic to merge the results of two operations.

Conclusion

The Teeing Collector in Java 12 is used for stream processing, which allows developers to perform multiple operations on a stream and combine their results efficiently. By using this collector, you can simplify your code and improve the performance of data processing tasks.

Summary:

  • Dual Collection: Perform two different operations on the same stream.
  • Result Combination: Combine results using a custom merger function.
  • Efficiency: Execute multiple operations in a single pass over the data.

By leveraging the Teeing Collector, you can enhance the readability and performance of your Java applications, especially when dealing with complex data processing tasks.

Leave a Comment

Scroll to Top