# 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. &lt;R&gt; R collect(Supplier&lt;R&gt; supplier, BiConsumer&lt;R, ? super T&gt; accumulator,BiConsumer&lt;R, R&gt; combiner)
2. &lt;R, A&gt; R collect(Collector&lt;? super T, A, R&gt; 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:

```Java
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());
```

The output is:

```Java
abcde
a, b, c, d, e
```

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.

```Java
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);
```

In the new list, there are only odd numbers:

```Java
[1, 3, 5, 7]
```

### 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**.

```Java
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);
```

This displays the output:

```Java
[2, 4, 6]
```

### Collect elements in a map with toMap()

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

```Java
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);
```

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

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

### 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 `""`.

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

The results are:

```Java
result1 ==> "abc"
result2 ==> "{a,b,c}"
```


This is a markdown version of: [https://www.ionos.com/en-ie/digitalguide/websites/web-development/java-stream-collect/](https://www.ionos.com/en-ie/digitalguide/websites/web-development/java-stream-collect/) for AI/LLM consumption.