Java streams 33. Collect 9. Collectors.groupingBy() collector

Terminal operation either returns one value (of the same or another type than the input type) or does not return anything at all (produces only side effects). It does not allow another operation to be applied afterward and closes the stream.

In this post, we will continue covering the last of the terminal operations called collect():

R collect(Collector<T,A,R> collector)

It is a specialization of the reduce() operation. It allows implementing a vast variety of algorithms using the ready-to-use collectors from the java.util.stream.Collectors class. We discussed how to create a custom collector in Java streams 25. Collect 1. Custom collector. In this article, we will use only the collectors produced by the Collectors class.



Creating Map object using Collectors.groupingBy() collector

Warning! The Collectors.groupingBy() collector is not concurrent. For parallel streams, the combiner function operates by merging the keys from one map into another, which can be an expensive operation. If it is not required that results are merged into the Map in the encountered order, a better parallel processing performance may be achieved using Collectors.toConcurrentMap() or Collectors.groupingByConcurrent() collector which we are going to discuss in the following articles.

There are several overloaded versions of factory methods that create the Collectors.groupingBy() collector:

Collector<T,?,Map<K,List<T>>> groupingBy(Function<T,K> classifier) – returns a Collector implementing a “group by” operation on input elements of type T, grouping elements according to a classification function, and returning the results in a Map;

Collector<T,?,Map<K,D>> groupingBy(Function<T,K> classifier, Collector<T,A,D> downstream) – returns a Collector implementing a cascaded “group by” operation on input elements of type T, grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector;

Collector<T,?,M> groupingBy(Function<T,K> classifier, Supplier<M> mapSupplier, Collector<T,A,D> downstream) – returns a Collector implementing a cascaded “group by” operation on input elements of type T, grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector.

The classifier function extracts from the element the value that is going to serve as a key in the resulting Map. This key is mapped to the value (List, by default, but can be any other object created by downstream function) that contains stream elements that yielded the same key.

The downstream is a collector that creates an object (mapped to the key produced by the classifier) where all elements that yielded the same key value are stored.

The mapSupplier is a function which, when called, produces a new empty Map of the desired type, used by the downstream to store the elements that yielded the same key value.

The following are the examples of the Collectors.groupingBy() usage: 

       
  Map<String, List<String>> map1 = Stream.of("cat", "fish", "cat", "dog")
       .collect(Collectors.groupingBy(Function.identity()));
  System.out.print(map1); // {fish=[fish], cat=[cat, cat], dog=[dog]}

  Map<Integer, List<String>> map2 = Stream.of("cat", "fish", "cat", "dog")
        .collect(Collectors.groupingBy(String::length));
  System.out.print(map2);   //prints: {3=[cat, cat, dog], 4=[fish]}

  Map<Integer, Set<String>> map3 = Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.groupingBy(String::length, Collectors.toSet()));
  System.out.print(map3);   //prints: {3=[cat, dog], 4=[fish]}

  Map<String, Long> map4 = Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.groupingBy(Function.identity(),
                                        Collectors.counting()));
  System.out.print(map4);    //prints: {fish=1, cat=2, dog=1}

  Map<Integer, Map<String, List<String>>> map5 = 
                            Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.groupingBy(String::length, 
                     Collectors.groupingBy(Function.identity())));
  System.out.print(map5); 
    //prints: {3={cat=[cat, cat], dog=[dog]}, 4={fish=[fish]}}

  Map<Integer, Map<String, Long>> map6 = 
                             Stream.of("cat", "fish", "cat", "dog")
     .collect(Collectors.groupingBy(String::length, 
                    Collectors.groupingBy(Function.identity(), 
                                        Collectors.counting())));
  System.out.print(map6);  //prints: {3={cat=2, dog=1}, 4={fish=1}}

  ConcurrentMap<Integer, Map<String, Long>> map7 =
                            Stream.of("cat", "fish", "cat", "dog")
     .collect(Collectors.groupingBy(String::length, 
                                     ConcurrentHashMap::new,  
                     Collectors.groupingBy(Function.identity(),
                                        Collectors.counting())));
  System.out.print(map7);  //prints: {3={cat=2, dog=1}, 4={fish=1}} 
        

In the next post, we will talk about creating a Map object using Collectors.toConcurrentMap() collector.

See other posts on Java 8 streams and posts on other topics.
You can also use navigation pages for Java stream related blogs:
— Java 8 streams blog titles
— Create stream
— Stream operations
— Stream operation collect()
The source code of all the code examples is here in GitHub

, ,

Send your comments using the link Contact or in response to my newsletter.
If you do not receive the newsletter, subscribe via link Subscribe under Contact.

Powered by WordPress. Designed by Woo Themes