1. Collecting elements

Finally, we've reached the most interesting method in the Stream class, the collect() method. It is used to move from streams to our familiar collections — List<T>, Set<T>, Map<T, R> and others.

The collect() method takes a special collector object as an argument. This object reads all the data from the stream, converts it to a specific kind of collection, and returns it. And then the collect method itself returns this collection.

All this is done in a rather slick manner: the collector object's type is Collector<T, A, R>. As you can see, it has three type parameters. The last type parameter (R) is usually a type like List<T>. This means the compiler can use this type to determine the correct return type for the collect() method itself.

I hope you're not too confused. In any case, you don't need to create Collector objects yourself. The ready-made objects returned by the static methods of the Collectors class will be sufficient.

Collectors class

The Collectors class has several static methods that return ready-made collector objects — something for every occasion. Here we'll consider the most important ones.

toList()
An object that converts a stream to a list (List<T>)
toSet()
An object that converts a stream to a set (Set<T>)
toMap()
An object that converts a stream to a map(Map<K, V>)
joining()
Concatenates the elements of a stream into a single string
mapping()
Converts the elements of a string to a Map<K, V>
groupingBy()
Groups the elements and returns Map<K, V>

2. Converting a stream to a list

The following is a typical example of working with a stream and converting the result to a list

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");

List<String> result = list.stream()
   .filter( s -> Character.isUpperCase(s.charAt(0)) )
   .collect( Collectors.toList() );

We got a stream from the collection. Then we got a new stream by retaining only strings whose first character is uppercase. Then all the data from that stream is collected into a collection, which is then returned.



3. Converting a stream to a set

The following is a typical example of working with a stream and converting the result to a set

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");

Set<String> result = list.stream()
   .filter( s -> Character.isUpperCase(s.charAt(0)) )
   .collect( Collectors.toSet() );

Everything is very similar to the code for converting a stream to a List, only we use a different collector object, which is returned by the toSet() method.



4. Converting a stream to a map

But converting a stream to a map is a little more difficult. Each entry in a Map consists of two elements: a key and a value. We need to figure out how we will define the key and value for each element in the stream.

Example:

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "a=2", "b=3", "c=4", "d==3");

Map<String, String> result = list.stream()
   .map( e -> e.split("=") )
   .filter( e -> e.length == 2 )
   .collect( Collectors.toMap(e -> e[0], e -> e[1]) );

Let's take a look at what's going on here.

In the first line, we use map(...) to convert each string into an array of strings. Using the split method, we split each string into two parts.

In the second line, we pass to the filter() method only those arrays that contain exactly two elements. The d==3 string gets split into an array of three elements, which does not match the filter.

And finally, in the last line, we convert the stream into a Map<String, String>. Two functions are passed to the toMap() method. For each element of the stream, the first function should return the key, and the second returns the value.

The first element of each array ("a", "b", "c") will be our key, and the second element of each array ("2", "3", "4") will be our value.



5. Converting a stream to a string

Another interesting collector object is returned by Collectors.joining(). It converts all elements of a stream to String and concatenates them into a single string. Example

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "a=2", "b=3", "c=4", "d==3");
String result = list.stream().collect( Collectors.joining(", ") );