What are collectors in Java Stream API?

In Java, the Collector is a concept in the Stream API which provides a way to collect the results of various operations in the stream.

It is used in conjunction with the collect method of the Stream interface. The collect method allows you to accumulate the elements of the stream into a summary result.

Here’s an example of how you can use a Collector:

package org.kodejava.stream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectToList {
    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("A", "AA", "AAA", "B", "BB", "BBB");
        List<String> collectedList = stringList.stream()
                .filter(s -> s.startsWith("A"))
                .collect(Collectors.toList());
    }
}

In the above example, the Collector used is Collectors.toList(), which will accumulate the stream’s elements into a List.

java.util.stream.Collectors is a utility class that contains various methods for creating common kinds of Collectors.

A Collector can perform transformations on the input elements, accumulation of processed input elements into a container, and combining of two result containers. In fact, Collector is extremely flexible, and you can supply Collector with your own functions for these purposes if you need to.

Collector is an interface in the java.util.stream package. It’s used along with the collect() terminal operation to consume elements from a stream and store them into a collection or possibly other types of result container.

public interface Collector<T, A, R> {
    Supplier<A> supplier();
    BiConsumer<A, T> accumulator();
    BinaryOperator<A> combiner();
    Function<A, R> finisher();
    Set<Characteristics> characteristics();
}

Each Collector contains four functions: supplier(), accumulator(), combiner(), and finisher(), and a characteristics set which provides hints for the implementation to optimize processing.

  1. Supplier: It creates a new mutable result container, where T is the type of items in the stream to be collected, and A is the type of the mutable accumulation container.
  2. Accumulator: It incorporates an additional input element into a result container.
  3. Combiner: It combines two result containers into one. This is used in parallel processing.
  4. Finisher: It performs the final transformation from the intermediate accumulation type A to the final result type R.
  5. Characteristics: It returns a Set of Collector.Characteristics indicating the characteristics of this Collector. This can be CONCURRENT, UNORDERED or IDENTITY_FINISH.

Here’s an example demonstrating how to create a custom collector:

package org.kodejava.stream;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collector;

public class CustomCollector {
    public static void main(String[] args) {
        Collector<String, ?, LinkedList<String>> toLinkedList =
                Collector.of(
                        LinkedList::new,              // The Supplier
                        LinkedList::add,              // The Accumulator
                        (left, right) -> {            // The Combiner
                            left.addAll(right);
                            return left;
                        },
                        Collector.Characteristics.IDENTITY_FINISH
                );

        List<String> strings = Arrays.asList("a", "b", "c", "d");
        LinkedList<String> collectedStrings = strings.stream()
                .collect(toLinkedList);
    }
}

In the built-in java.util.stream.Collectors class, there are various static methods which return Collector instances for common use cases, such as toList(), toSet(), joining(), groupingBy(), partitioningBy(), and others.

Wayan

Leave a Reply

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