Collectors Class In Java

The class Collectors is a subclass of the Object class and serves as a concluding class. It offers functionalities for reducing operations, like gathering elements into collections, summarizing elements based on different criteria, and more.

The Collectors class is a component of the java.util.stream package in Java. This indicates that it is integrated into the Stream API that was added in Java 8. This class enables the execution of aggregate tasks on collections using a functional programming approach.

Purpose of the Collectors Class

The main objective of the Collectors class is to serve as a provider for Collector implementations that are frequently beneficial for reduction processes. It enables the transformation of a stream into different collection formats (such as List, Set, or Map), execute grouping, partitioning, summarizing, and even basic string concatenation.

Java Collectors Class Methods

The Collectors class in Java offers a range of methods for handling elements.

Methods Description
public static public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) CollectorCollector averagingDouble(ToDoubleFunction<? super T> mapper) It returns a Collector that produces the arithmetic mean of a double-valued function applied to the input elements. If no elements are present, the result is 0. The method is useful when you want to calculate average values, such as average salary or average rating, from a stream of objects.
public static <T> CollectorCollector<T, ?, T> reducing(T identity, BinaryOperator<T> op) It returns a Collector that performs a reduction of its input elements under a specified BinaryOperator using the provided identity. The identity value is used as a starting point, and then the reduction operator is applied cumulatively to combine all the elements.
public static <T, ?> CollectorCollector<T, ?, T>> reducing(BinaryOperatorBinaryOperator<T> op) It returns a Collector that performs a reduction of its input elements under a specified BinaryOperator. The result is described as an Optional<T>. The version does not require an identity value and returns an Optional, which is empty if the stream is empty.
public static <T, ?> CollectorCollector<T, ?, T> reducing(U identity, FunctionFunction<? super T> mapper, BinaryOperatorBinaryOperator<T> op) It returns a Collector that performs a reduction of its input elements under a specified mapping function and BinaryOperator. It is a generalization of reducing(Object, BinaryOperator), which allows a transformation of the elements before reduction. It is especially useful when you need to convert elements before reducing them.
public static <T> CollectorCollector<T, ?, Map<K, List<T>>>>> groupingBy(FunctionFunction<? super T, ? extends K> classifier) It returns a Collector implementing a "group by" operation on input elements of type T, grouping elements according to a classification function, and returning the results in a Map. It is one of the most frequently used methods for grouping elements in a stream based on a property, like grouping people by city or employees by department.
public static <T, Map<K, List<T>>> CollectorCollector<T, ?, Map<K, List<T>>>> groupingBy(FunctionFunction<? super T, ? extends K> classifier, CollectorCollector<? super T, A, R> downstream) It returns a Collector implementing a cascaded "group by" operation on input elements of type T, grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector. It enables complex multi-level grouping and aggregation, such as grouping by category and summing quantities.
public static <T, Map<K, List<T>>>> CollectorCollector<T, ?, Map<K, List<T>>> groupingBy(FunctionFunction<? super T, ? extends K> classifier, SupplierSupplier<? extends Map<K, List<T>>> mapFactory, CollectorCollector<? super T, A, R> downstream) It returns a Collector implementing a cascaded "group by" operation on input elements of type T, grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector. The Map produced by the Collector is created with the supplied factory function. The method provides full control over the map type used (e.g., LinkedHashMap, TreeMap) and how grouped values are processed.
public static <Collector<T, ?, Map<K, List<T>>> CollectorCollector<K, List<T>>>> groupingByConcurrent(Function<? super T,? extends K> classifier) It returns a concurrent Collector implementing a "group by" operation on input elements of type T, grouping elements according to a classification function. It is designed for parallel stream processing and produces thread-safe groupings using ConcurrentMap.
public static <Collector<T, ?, Map<K, List<T>>> CollectorCollector<T, ?, Map<K, List<T>>>> groupingByConcurrent(FunctionFunction<? super T, ? extends K> classifier, CollectorCollector<? super T, A, R> downstream) It returns a concurrent Collector implementing a cascaded "group by" operation on input elements of type T, grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector.
public static <T, Map<K, List<T>>>> CollectorCollector<T, ?, Map<K, List<T>>> groupingByConcurrent(FunctionFunction<? super T, ? extends K> classifier, SupplierSupplier<? extends ConcurrentMap<K, List<T>>> mapFactory, CollectorCollector<? super T, A, R> downstream) It returns a concurrent Collector implementing a cascaded "group by" operation on input elements of type T, grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector. The ConcurrentMap produced by the Collector is created with the supplied factory function.
public static <Collector<T, ?, Map<Boolean, List<T>>> CollectorCollector<T, Map<Boolean, List<T>>>>> partitioningBy(PredicatePredicate<? super T> predicate) It returns a Collector that partitions the input elements according to a Predicate and organises them into a Map<Boolean, List<T>>. There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned.
public static <T> CollectorCollector<T, ?, Map<Boolean, List<T>>>> partitioningBy(PredicatePredicate<? super T> predicate, CollectorCollector<T, ?, Map<Boolean, List<T>>> downstream) It returns a Collector that partitions the input elements according to a Predicate, reduces the values in each partition according to another Collector, and organises them into a Map<Boolean, List<T>>. There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned.
public static <T,D,A> Collector<T,?,Map<Boolean,D>> partitioningBy(Predicate<? super T> predicate, Collector<? Super T,A,D> downstream) It returns a Collector that partitions the input elements according to a Predicate, reduces the values in each partition according to another Collector, and organises them into a Map<Boolean, D> whose values are the result of the downstream reduction.
public static <Collector<T, ?, Map<K, V>>> CollectorCollector<T, ?, Map<K, V>>> toMap(FunctionFunction<? super T, ? extends K> keyMapper, FunctionFunction<? super T, ? extends R> valueMapper) It returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements. If duplicate keys are encountered, an IllegalStateException is thrown unless a merge function is provided.
public static <T, K, V> CollectorCollector<T, ?, Map<K, V>>> toMap(FunctionFunction<? super T, ? extends K> keyMapper, FunctionFunction<? super T, ? extends R> valueMapper, BinaryOperatorBinaryOperator<? super R> mergeFunction) It returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.
public static <T, K, V>> CollectorCollector<T, ?, Map<K, V>> toMap(FunctionFunction<? super T, ? extends K> keyMapper, FunctionFunction<? super T, ? extends D> valueMapper, BinaryOperatorBinaryOperator<? super D> mergeFunction, Supplier<Supplier<Map<K, V>>> mapSupplier) It returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.
public static public static <T, K, V> Collector<T, ?, ConcurrentMap<K, V>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends V> valueMapper) Collector<Collector<T, K, V>>> toConcurrentMap(FunctionFunction<? super T, ? extends K> keyMapper, FunctionFunction<? super T, ? extends V> valueMapper) It returns a concurrent Collector that accumulates elements into a ConcurrentMap whose keys and values are the result of applying the provided mapping functions to the input elements.
public static <T, K, V> CollectorCollector<T, ?, ConcurrentMap<K, V>>> toConcurrentMap(FunctionFunction<? super T, ? extends K> keyMapper, FunctionFunction<? super T, ? extends V> valueMapper, BinaryOperatorBinaryOperator<? super V> mergeFunction) It returns a concurrent Collector that accumulates elements into a ConcurrentMap whose keys and values are the result of applying the provided mapping functions to the input elements.
public static <T, K, V>> CollectorCollector<T, ?, ConcurrentMap<K, V>> toConcurrentMap(FunctionFunction<? super T, ? extends V> keyMapper, FunctionFunction<? super T, ? extends V> valueMapper, BinaryOperatorBinaryOperator<? super V> mergeFunction, SupplierSupplier<Map<K, V>> mapSupplier) It returns a concurrent Collector that accumulates elements into a ConcurrentMap whose keys and values are the result of applying the provided mapping functions to the input elements. Highly customizable for advanced parallel operations.
public static public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) CollectorCollector<T, IntSummaryStatistics> summarizingInt(ToIntFunctionToIntFunction<? super T> mapper) It returns a Collector that applies an int-producing mapping function to each input element and returns summary statistics for the resulting values.
public static public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) CollectorCollector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) It returns a Collector that applies a long-producing mapping function to each input element and returns summary statistics for the resulting values. Includes count, sum, min, max, and average in one pass.
public static <Collector<T, ?, DoubleSummaryStatistics> CollectorCollector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) It returns a Collector that applies a double-producing mapping function to each input element and returns summary statistics for the resulting values. Efficient for collecting average, count, max, min, and sum in a single operation.
public static public static <T> Collector<T, ?, List<T>> toList() Collector<Collector<T, ?, List<T>>> toList() It returns a Collector that accumulates the input elements into a new List. This is one of the most commonly used collectors.
public static public static <T> Collector<T, ?, Set<T>> toSet() Collector<Collector<T, ?, Set<T>>> toSet() It returns a Collector that accumulates the input elements into a Set, removing duplicates in the process.
public static public static <T> Collector<T, ?, String> joining() CollectorCollector<T, ?, String> joining() It returns a Collector that concatenates the input elements into a single String in encounter order. Only works on streams of CharSequence or where toString() is meaningful.
public static public static <T> Collector<T, ?, String> joining(CharSequence delimiter) CollectorCollector<T, ?, String> joining(CharSequence delimiter) It returns a Collector that joins CharSequence elements using the given delimiter. Useful for building comma-separated strings.
public static <T> CollectorCollector<String, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) It extends joining(delimiter) by allowing an optional prefix and suffix. Useful for building JSON-like or SQL-like string structures.
public static <T> CollectorCollector<T, ?, Long> counting() It returns a Collector that counts the number of input elements. Often used for simple statistics.

Examples

Example 1: Fetching Data as a List

Example

Example

import java.util.stream.Collectors;  

import java.util.List;  

import java.util.ArrayList;  

class Product {  

    int id;  

    String name;  

    float price;  

    public Product(int id, String name, float price) {  

        this.id = id;  

        this.name = name;  

        this.price = price;  

    }  

} 

public class Main {  

    public static void main(String[] args) {  

        List<Product> productsList = new ArrayList<Product>();  

        // Adding Products  

        productsList.add(new Product(1, "HP Laptop", 25000f));  

        productsList.add(new Product(2, "Dell Laptop", 30000f));  

        productsList.add(new Product(3, "Lenevo Laptop", 28000f));  

        productsList.add(new Product(4, "Sony Laptop", 28000f));  

        productsList.add(new Product(5, "Apple Laptop", 90000f));  

        // **Converting product prices into a List using Collectors**

        List<Float> productPriceList = productsList.stream()  

                .map(x -> x.price)                 // fetching only the price  

                .collect(Collectors.toList());     // **collecting into a List**

        System.out.println(productPriceList);  

    }  

}

Output:

Output

[25000.0, 30000.0, 28000.0, 28000.0, 90000.0]

Explanation

The map function is utilized to retrieve the price of each item, followed by employing Collectors.toList to gather these prices into a List<Float>.

The time complexity of the algorithm is O(n), with n representing the total products in the list. Each individual product undergoes processing exactly once.

Example 2: Converting Data as a Set

Example

Example

import java.util.stream.Collectors;  

import java.util.Set;  

import java.util.List;  

import java.util.ArrayList;  

class Product{  

    int id;  

    String name;  

    float price;  

    public Product(int id, String name, float price) {  

        this.id = id;  

        this.name = name;  

        this.price = price;  

    }  

}  

public class Main {  

    public static void main(String[] args) {  

        List<Product>productsList = new ArrayList<Product>();  

        //Adding Products  

        productsList.add(new Product(1,"HP Laptop",25000f));  

        productsList.add(new Product(2,"Dell Laptop",30000f));  

        productsList.add(new Product(3,"Lenevo Laptop",28000f));  

        productsList.add(new Product(4,"Sony Laptop",28000f));  

        productsList.add(new Product(5,"Apple Laptop",90000f));  

        Set<Float>productPriceList =   

                productsList.stream().map(x->x.price)         // fetching price  

                            .collect(Collectors.toSet());   // collecting as list  

        System.out.println(productPriceList);  

    }  

}

Output:

Output

[25000.0, 30000.0, 28000.0, 90000.0]

Explanation

In this scenario, we utilize Collectors.toSet in place of toList to eliminate duplicate prices. By leveraging a Set, which doesn't permit duplicates, the resulting collection only retains unique prices.

The time complexity for streaming data and inserting it into a HashSet is O(n).

Example 3: Using the sum Method

Example

Example

import java.util.stream.Collectors;  

import java.util.List;  

import java.util.ArrayList;  

class Product {  

    int id;  

    String name;  

    float price;  

    public Product(int id, String name, float price) {  

        this.id = id;  

        this.name = name;  

        this.price = price;  

    }  

}  

public class Main {  

    public static void main(String[] args) {  

        List<Product> productsList = new ArrayList<Product>();  

        // Adding Products  

        productsList.add(new Product(1, "HP Laptop", 25000f));  

        productsList.add(new Product(2, "Dell Laptop", 30000f));  

        productsList.add(new Product(3, "Lenevo Laptop", 28000f));  

        productsList.add(new Product(4, "Sony Laptop", 28000f));  

        productsList.add(new Product(5, "Apple Laptop", 90000f));  

        // **Summing all prices using summingDouble**

        Double sumPrices = productsList.stream()  

                .collect(Collectors.summingDouble(x -> x.price));  

        System.out.println("Sum of prices: " + sumPrices);  

        // **Summing all IDs using summingInt**

        Integer sumId = productsList.stream()  

                .collect(Collectors.summingInt(x -> x.id)); 

        System.out.println("Sum of id's: " + sumId);  

    }  

}

Output:

Output

Sum of prices: 201000.0

Sum of id's: 15

Explanation

The method Collectors.summingDouble is utilized for totaling prices, while summing IDs can be achieved using Collectors.summingInt. These collectors are specifically designed to assist in aggregating numerical data.

The time complexity of this algorithm is O(n) because every element is visited once to calculate the total sum.

Example 4: Getting Product Average Price

Example

Example

import java.util.stream.Collectors;  

import java.util.List;  

import java.util.ArrayList;  

class Product {  

    int id;  

    String name;  

    float price;  

    public Product(int id, String name, float price) {  

        this.id = id;  

        this.name = name;  

        this.price = price;  

    }  

}  

public class Main {  

    public static void main(String[] args) {  

        List<Product> productsList = new ArrayList<Product>();  

        // Adding Products  

        productsList.add(new Product(1, "HP Laptop", 25000f));  

        productsList.add(new Product(2, "Dell Laptop", 30000f));  

        productsList.add(new Product(3, "Lenevo Laptop", 28000f));  

        productsList.add(new Product(4, "Sony Laptop", 28000f));  

        productsList.add(new Product(5, "Apple Laptop", 90000f));  

        // **Calculating average price using averagingDouble**

        Double average = productsList.stream()  

                .collect(Collectors.averagingDouble(p -> p.price));  

        System.out.println("Average price is: " + average);  

    }  

}

Output:

Output

Average price is: 40200.0

Explanation

The averagingDouble collector computes the mean of the prices by adding up all the elements and then dividing the total by the count.

The time complexity is O(n) as each product is iterated over once in order to calculate both the sum and count.

Example 5: Counting Elements

Example

Example

import java.util.stream.Collectors;  

import java.util.List;  

import java.util.ArrayList;  

class Product {  

    int id;  

    String name;  

    float price;  

    public Product(int id, String name, float price) {  

        this.id = id;  

        this.name = name;  

        this.price = price;  

    }  

    public int getId() {  

        return id;  

    }  

    public String getName() {  

        return name;  

    }  

    public float getPrice() {  

        return price;  

    }  

}  

public class Main {  

    public static void main(String[] args) {  

        List<Product> productsList = new ArrayList<Product>();  

        // Adding Products  

        productsList.add(new Product(1, "HP Laptop", 25000f));  

        productsList.add(new Product(2, "Dell Laptop", 30000f));  

        productsList.add(new Product(3, "Lenevo Laptop", 28000f));  

        productsList.add(new Product(4, "Sony Laptop", 28000f));  

        productsList.add(new Product(5, "Apple Laptop", 90000f)); 

        // **Counting total elements using Collectors.counting()**

        Long noOfElements = productsList.stream()  

                .collect(Collectors.counting());  

        System.out.println("Total elements : " + noOfElements);  

    }  

}

Output:

Output

Total elements: 5

Explanation

The Collectors.counting terminal collector is used to determine the total count of elements present in the stream.

The time complexity of this algorithm is classified as O(n), with n representing the total count of products in the dataset.

Advantages of Using Collectors

  • Concise and readable code for common operations.
  • Improved performance through internal iteration and one-pass computation.
  • Easy integration with parallel streams using groupingByConcurrent and toConcurrentMap.
  • Highly customizable for advanced data processing.
  • Java Collectors MCQs

  1. Which of the following is a valid purpose of the Collectors class in Java?
  • To perform mathematical computations
  • To perform reduction operations on streams
  • To handle exceptions in streams
  • To open files in Java

Explanation: The Collectors class provides various static methods to perform reduction operations, such as toList, groupingBy, and averagingDouble.

  1. What does the Collectors.toList method return?
  • An array
  • A stream
  • A List containing the stream elements
  • A Set containing the stream elements

Explanation: Collectors.toList collects the elements of the stream into a List.

  1. Which method from Collectors is used to group elements by a classifier function?
  • toMap
  • groupingBy
  • partitioningBy
  • averagingDouble

Explanation: Collectors.groupingBy is used to group stream elements by a classifier function and collect them into a Map.

  1. What is returned by Collectors.averagingDouble?
  • A stream of doubles
  • An integer average
  • A Collector that calculates the average of double values
  • A map of double averages

Explanation: This method returns a Collector that calculates the average of double values from the stream elements.

  1. What does partitioningBy return?
  • A list of partitions
  • A Map<Boolean, List<T>>
  • A Map<Integer, List<T>>
  • A single boolean result

The method Collectors.partitioningBy divides elements into two categories according to a given Predicate and presents them as a Map<Boolean, List<T>.

Input Required

This code uses input(). Please provide values below: