Friday, 15 June 2018

Java 8 - Stream.collect() Example

The collect() method of Stream class can be used to accumulate elements of any Stream into a Collection. In Java 8, you will often write code which converts a Collection e.g. List or Set to Stream and then applies some logic using functional programming methods like the filter, map, flatMap and then converts the result back to the Collection e.g. List, Set or Map. In this last part, the collect() method of Stream helps. It accepts a Collector to accumulate elements of Stream into specified Collection. The Collector class provides different methods e.g. toList(), toSet(), toMap(), and toConcurrentMap() to collect the result of Stream into List, Set, Map, and ConcurrentMap in Java.

It also provides a special toCollection() method which can be used to collect Stream elements into a specified Collection e.g. ArrayList, Vector, LinkedList or HashSet.

In this article, we'll see a couple of examples of Stream's collector method to collect the result of stream processing into a List, Set, and Map in Java.


1. Stream to List using collect()

You can collect the result of a Stream processing pipeline in a list by using the Collectors.toList() method. Just pass the Collectors.toList() to collect() method as shwon below:

List<String> listOfStringStartsWithJ
 = listOfString
     .stream()
     .filter( s -> s.startsWith("J"))
     .collect(Collectors.toList());


The list returned by the collect method will have all the String which starts with "J" in the same order they appear in the original list because both Stream and List keep elements in order.

1. Stream to Set using toSet()

You can use Collectors.toSet() method along with collect() to accumulate elements of a Stream into a Set. Since Set doesn't provider ordering and doesn't allow duplicate, any duplicate from Stream will be discarded and order of elements will be lost.

Here is an example to convert Stream to Set using collect() and Collectors in Java 8:

Oracle Java Tutorials and Materials, Oracle Java Guides, Oracle Java Learning
The set of String in this example contains all the String which starts with letter C e.g. C and C++. The order will be lost and any duplicate will be removed.

3. Stream to Map using toMap()

You can create a Map from elements of Stream using collect() and Collectors.toMap() method. Since Map store two objects i.e. key and value and Stream contains just one element, you need to provide the logic to extract key and value object from Stream element.

For example, if you have a Stream of String then you can create a Map where the key is String itself and value is their length, as shown in the following example:

Map<String, Integer> stringToLength
   = listOfString
        .stream()
        .collect(
            Collectors.toMap(Function.identity(), String::length));

The Function.identity() used here denotes that same object is used as a key. Though you need to be a little bit careful since Map doesn't allow duplicate keys if your Stream contains duplicate elements than this conversion will fail.

In that case, you need to use another overloaded toMap() method also accepts an argument to resolve conflict in case of duplicate keys. Also, toMap() doesn't provide any guarantee on what kind of Map is returned.

3. Stream to Collection using toCollection()

You can also collect or accumulate result of Stream processing into Collection of your choice e.g ArrayList, HashSet, or LinkedList. There is also a toCollection() method in the Collectors class which allows you to convert Stream to any collection. In the following example, we will learn how to collect Stream elements into an ArrayList.

ArrayList<String> stringWithLengthGreaterThanTwo
  = listOfString
      .stream()
      .filter( s -> s.length() > 2)
      .collect(Collectors.toCollection(ArrayList::new));

Since ArrayList is a list, it provides ordering guarantee, hence all the elements in the ArrayList will be in the same order they appear in original List and Stream.

Java Program to Use Stream.collect() method


Here is our complete Java program to demonstrate the use of collect() method of Stream class to convert Stream into different Collection classes in Java e.g. List, Set, Map, and Collection itself.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Code {

  public static void main(String[] args) {

    List<String> listOfString = Arrays.asList("Java", "C", "C++", "Go",
        "JavaScript", "Python", "Scala");
    System.out.println("input list of String: " + listOfString);

    // Example 1 - converting Stream to List using collect() method
    List<String> listOfStringStartsWithJ
                              = listOfString.stream()
                                            .filter(s -> s.startsWith("J"))
                                            .collect(Collectors.toList());

    System.out.println("list of String starts with letter J: "
        + listOfStringStartsWithJ);

    // Example 2 - converting Stream to Set
    Set<String> setOfStringStartsWithC
                      = listOfString.stream()
                                    .filter(s -> s.startsWith("C"))
                                    .collect(Collectors.toSet());

    System.out.println("set of String starts with letter C: "
        + setOfStringStartsWithC);

    // Example 3 - converting Stream to Map
    Map<String, Integer> stringToLength
                          = listOfString.stream()
                                         .collect(Collectors.toMap(Function.identity(),
                                                                    String::length));
    System.out.println("map of string and their length: " + stringToLength);

    // Example - Converting Stream to Collection e.g. ArrayList
    ArrayList<String> stringWithLengthGreaterThanTwo
                        = listOfString.stream()
                                      .filter(s -> s.length() > 2)
                                      .collect(Collectors.toCollection(ArrayList::new));
    System.out.println("collection of String with length greather than 2: "
        + stringWithLengthGreaterThanTwo);

  }
}

Output
input list of String:
[Java, C, C++, Go, JavaScript, Python, Scala]
list of String starts with letter J:
[Java, JavaScript]
set of String starts with letter C:
[C++, C]
map of string and their length:
{Java=4, C++=3, C=1, Scala=5, JavaScript=10, Go=2, Python=6}
collection of String with length greather than 2:
[Java, C++, JavaScript, Python, Scala]

That's all about how to use the collect() method of Stream class in Java 8. Along with collect(), you can use Collectors method to convert Stream to List, Set, Map, or any other Collection of your choice. Just explore the Collectors Javadoc to learn more about those methods.

Related Posts