How to use Java collect() to collect and process data

Stream Collectors are a powerful feature in the Java 8 Stream API that allow you to collect and process data efficiently. Here we’ll explain their structure and how the Java collect() method can be used.

How can Java collect() be used?

A Stream Collector can be used to create a list, set, or map from a stream. A stream is a sequence of elements that are processed one after another. The Collector interface provides a set of reduction operations for data in a stream pipeline. These are terminal operations that collect and merge the results of intermediate steps.

Collectors can be used to filter or sort objects from a stream. Aggregation is also possible, such as summing numbers, combining strings, or counting elements. In addition, Collectors have functions that can transform the contents of a stream into a specific structure. You can transform a list into a map, for example. Groupings help categorise elements with certain properties or conditions. Most importantly, Stream Collectors have the advantage that they can process data at the same time using multiple threads. This enables operations to be performed much faster and more efficiently, especially with large amounts of data.

What is the syntax for Java collect()?

The method accepts a Collector that describes how the elements of the stream should be collected and aggregated as an argument. A Collector is an interface that provides various methods to aggregate stream elements into a specific form, for example, into a list, a set or a map.

There are two variants of the Java Stream collect() method:

  1. <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

The first variant has three functions as arguments:

  • supplier: creates a container that will be used for intermediate results
  • accumulator: calculates the final result
  • combiner: combines the results of parallel stream operations

These predefined Collectors are already included in the standard library and can easily be imported and used.

The second variant accepts a Collector as an argument and returns a result.

  • R: the type of result
  • T: the type of elements in the stream
  • A: the type of accumulator that stores the intermediate state of the collector operation
  • collector: executes the reduction operation.

By using this variant, developers can create customised Collectors that are specifically tailored to their requirements and provide greater flexibility and control over the reduction process.

What are practical examples for using Java collect()?

Below we illustrate various functions of the Stream.collect() method. You should already be familiar with the basic Java operators before jumping into the collection framework.

Concatenate a list of strings

With Java Collect(), we can concatenate a list of strings to get a new string:

List<String> letters = List.of("a", "b", "c", "d", "e");
// without combiner function
StringBuilder result = letters.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append(",").append(b));
System.out.println(result.toString());
// with combiner function
StringBuilder result1 = letters.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append(",").append(b));
System.out.println(result1.toString());
Java

The output is:

abcde
a, b, c, d, e
Java

In the first calculation, only one StringBuilder instance was used and there was no combiner function. This is why the result is abcde.

In the second output, the combiner function merged the StringBuilder instances and separated them with a comma.

Collect elements in a list with toList()

We can use the filter() function to select certain elements of a list and then use toList() to store them in a new list.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
List<Integer> oddNumbers = numbers.stream().filter(x -> x % 2 != 0).collect(Collectors.toList());
System.out.println(oddNumbers);
Java

In the new list, there are only odd numbers:

[1, 3, 5, 7]
Java

Collect elements in a set with toSet()

Similarly, we can select elements and create a new set from them. The elements in a set don’t have to be arranged in a specific order.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
Set<Integer> evenNumbers = numbers.parallelStream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
System.out.println(evenNumbers);
Java

This displays the output:

[2, 4, 6]
Java

Collect elements in a map with toMap()

A map can be used together with Java collect() to assign a value to each key.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
Map<Integer, String> mapEvenNumbers = numbers.parallelStream().filter(x -> x % 2 == 0)
    .collect(Collectors.toMap(Function.identity(), x -> String.valueOf(x)));
System.out.println(mapEvenNumbers);
Java

In the output, we can see that each even number in the input has been assigned a value that is identical to it:

{2=2, 4=4, 6=6}
Java

Combine elements in a string with joining()

The joining() method combines elements in a stream in the order in which they appear and uses a separator to separate the elements. The separator is passed as an argument to joining(). If no separator is specified, joining() uses the empty string "".

jshell> String result1 = Stream.of("a", "b", "c").collect(Collectors.joining());
jshell> String result2 = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}"));
Java

The results are:

result1 ==> "abc"
result2 ==> "{a,b,c}"
Java
Was this article helpful?
Page top