Sunday, April 2, 2023

How to use map + flatMap + Collectors.toSet() in Java? Example Tutorial

Hello guys, I was searching for a good example of flatMap online but didn't found a good one, so created my own. As name suggest flatMap is used to flatten stream like unwinding multiple list of values. For example you have a Stream of List of Integer and you want to create Stream of Integer by unwinding those list, you can do that using FlatMap function from java.util.Stream class. Coming back to flatMap, its actually a general concept which is available in other functional programming language like Scala. Just like map() function works by applying a function to each element in the Stream, flatMap works by applying a function that returns a sequence for each element in the list, and flattening the results into Stream or another list. 

It can be understand easily if you know how Map works in functional programming, so let first see that,  by using map function in Java we can transform list of (2,3,5,7,11) into list (4,9,15,49,121) where each element is squared.as simple as that flat can convert list of list of String into a list of Integer by transforming or converting String to number and flattening a List of List into a bigger and single List.

Actually this flattening happens at Stream level and you can collect all the elements into a List or Set or any other object using Collectors. In this example, we have used Collectors.toList() to collect all the elements into a List. 

It said that a picture is worth a thousand worth, here is a picture which explains flatMap, now you tell me in comments whether this picture is worth a thousand word? did you understand how flatmap method works by looking at this diagram? I would love to hear your thoughts

If you are still not clear then let me explain this diagram to you in few words. In this diagram, we pass a function to flatMap() method which convert a circle to diamond. Then we apply this flatMap to a Stream of circle. flatMap then convert that stream of circle object to stream of diamond using the function we supplied. 




When and How to use flatMap in Java 8 Stream? Example 

When you have list of list and you want to flat that into a single list then you can use flatMap method, same goes for set of set or Collection of Collection.

FlatMap + Collector Example in Java 8 - List of Object and Stream Example

Here is the complete code example:


package test;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Java Program to demonstrate how to use flatMap in Java 8.
 * As name suggests flatMap is used to flatten a collection of collection e.g.
 * list of list of numbers.
 *
 * @author Javin
 */
public class FlatMapDemoInJava8 {

    public static void main(String args[]) {

        // p1 has three notes of 1,5 and 10
        Person p1 = new Person("P1");
        p1.add(1);
        p1.add(5);
        p1.add(10);
       
        // p2 has five notes of 10,20,50 and 5
        Person p2 = new Person("P2");
        p2.add(10);
        p2.add(20);
        p2.add(50);
        p2.add(5);
       
        // Now, let's find out how many different note team has
        List team = new ArrayList<>();
        team.add(p1);
        team.add(p2);
       
        Set setOfDistinctNote = team.stream()
                                               .map( p -> p.getNotes())
                                               .flatMap(l -> l.stream())
                                               .collect(Collectors.toSet());
       
        System.out.println("Number of distinct notes in team : " + setOfDistinctNote);
    }

}

class Person{
    private String name;
    private List notes = new ArrayList<>();
   
    public Person(String name){
        this.name = name;
    }
   
    public void add(Integer note){
        notes.add(note);
    }

    public List getNotes(){
        return notes;
    }
   
    @Override
    public String toString() {
        return String.format(name + notes);
    }  
   
}

Output
Number of distinct notes in team : [1, 50, 20, 5, 10]





Difference between map() and flatMap() methods in Java

The following examples show the differences between map and flatMap on a sequence of String, although examples are given in Scala programming language but it applicable to Java as well. 

scala> val fruits = Seq("apple", "banana", "orange")
fruits: Seq[java.lang.String] = List(apple, banana, orange)

scala> fruits.map(_.toUpperCase)
res0: Seq[java.lang.String] = List(APPLE, BANANA, ORANGE)

scala> fruits.flatMap(_.toUpperCase)
res1: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)


Quite a difference, no? Because flatMap treats a String as a sequence of Char, it flattens the resulting list of strings into a sequence of Char. flatMap is a combination of map and flatten, so it first runs map on the sequence, then runs flatten, giving the result shown.

You can also see  the difference between map and flatMap in Java for a simple String to integer conversion example. Here is a nice diagram which also explains the difference between map and flatmap in Java clearly. 





That's all about how to use flatMap function with collector in Java. You can use flatmap to both flatten and transform an object. For example, if you have a list of list of String then you can convert that into a list of Integer using flatMap function in Java. Map is used to apply a function to each element of list to transform that, while flatMap is used to flatten a Stream of Stream into a Stream of something like number, String or whatever. 


I suggest you try to practice flatMap function with simple exercises like converting List of List of String to List of Integer and so on to master this concept and List of List of Employees to List of their Department etc. 

No comments:

Post a Comment