Stream Col­lec­tors are a powerful feature in the Java 8 Stream API that allow you to collect and process data ef­fi­cient­ly. 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 op­er­a­tions for data in a stream pipeline. These are terminal op­er­a­tions that collect and merge the results of in­ter­me­di­ate steps.

Col­lec­tors can be used to filter or sort objects from a stream. Ag­gre­ga­tion is also possible, such as summing numbers, combining strings, or counting elements. In addition, Col­lec­tors 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 cat­e­go­rize elements with certain prop­er­ties or con­di­tions. Most im­por­tant­ly, Stream Col­lec­tors have the advantage that they can process data at the same time using multiple threads. This enables op­er­a­tions to be performed much faster and more ef­fi­cient­ly, es­pe­cial­ly 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 ag­gre­gat­ed 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, Bi­Con­sumer<R, ? super T> ac­cu­mu­la­tor,Bi­Con­sumer<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 in­ter­me­di­ate results
  • ac­cu­mu­la­tor: Cal­cu­lates the final result
  • combiner: Combines the results of parallel stream op­er­a­tions

These pre­de­fined Col­lec­tors 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 ac­cu­mu­la­tor that stores the in­ter­me­di­ate state of the collector operation
  • collector: Executes the reduction operation.

By using this variant, de­vel­op­ers can create cus­tomized Col­lec­tors that are specif­i­cal­ly tailored to their re­quire­ments and provide greater flex­i­bil­i­ty and control over the reduction process.

What are practical examples for using Java collect()?

Below we il­lus­trate various functions of the Stream.collect() method. You should already be familiar with the basic Java operators before jumping into the col­lec­tion framework.

Con­cate­nate a list of strings

With Java Collect(), we can con­cate­nate 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 cal­cu­la­tion, only one String­Builder 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 String­Builder 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
Go to Main Menu