Friday, October 1, 2021

Java 8 Stream + FlatMap Example for Beginners | How to flat a list of list in Java?

In order to understand the flatMap() method, you first need to understand the map() function of Java 8. The map() function is declared in  the java.util.stream.Stream class and uses to transform one Stream into another, for example, it can convert a stream of integer numbers into another stream of ints where each element is the square of the corresponding element in the source stream. In the map() operation, a function is applied to each element of the source Stream and return values are inserted into a new Stream which is returned to the caller. The key point to note here is that the function used by the map() operation returns a single value.

Now, if the map operation uses a function which instead of returning a single value returns a Stream of values like when you give a number and it returns all prime factors of the number then you have a Stream of Stream of integers. That's where the flatmap function helps.

The flatMap() method can be used to flatten that stream into a stream of integers. For example, suppose, you have a list of numbers like [21, 23, 42] and we call the getPrimeFactors() method along with the map() operation to transform this stream.

The result would be [[3,7],[23],[2,3,7]]. If you want to flatten this stream of a stream into a stream of values, you can use the flatMap() which will finally return [3,7,2,3,2,3,7].

In short, the flatMap() function is used to convert a Stream of Stream into a list of values. If you want to learn these functions better and in general Java better, I suggest you join a comprehensive course like The Complete Java MasterClass on Udemy, which is recently updated to cover Java 11.





How flatMap works in Java 8?

If you haven't got the whole picture and struggle to understand how exactly the flatMap function works then here is a diagram, which may help you to clear your debut. It's said that a picture is worth a thousand words and this is true, the following image explains how flatMap works in Java 8 quite easily:

Java 8 flatMap example with streams

You can see that there are two lists, one is denoted with red color while the other is denoted with green color, both of them contain three elements each. Once you apply flatMap on them, you can get another list that contains elements from them.

You can see that in the second pipe where we have 3 elements from green lists denoted by 1, 2, and 3, and another three elements from red lists which is denoted by 4, 5, and 6.

Btw, if you need hands-on online training to master functional programming in Java 8, consider joining Refactoring to Java 8 Streams and Lambdas Online Self- Study Workshop from Heinz Kabutz. He is a Java Champion and one of the best Java instructors, many of you might have attended his Java Concurrency or Java Design pattern courses.




Java 8 FlatMap Example - Flat Stream of Stream in Java

Here is a sample Java program to demonstrate how to use the flatMap() function in Java 8. As I told you, you can use the flatMap() to flatten a Stream of Stream of values into just a Stream of values.

In our example, we have a Stream of the list of String and by using the flatMap() we convert this into just a Stream of String to get the full list of players participating in the cricket world cup.

This operation is really useful to get the full list by combining several small lists. For more details, you can also join What's New in Java 8 course on Pluralsight to learn new features of Java 8 like lambda expression, streams, new Date and Time API, and other enhancements.

Here is our Java program to demonstrate how to use the Stream.flatMap() in Java 8.

package test;

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

/**
 * Java Program to demonstrate how to use the flatMap() function in Java 8.
 * The flatMap() function is used to convert a Stream of list of values to
 * just a Stream of values. This is also called flattening of stream.
 *
 * @author Javin Paul
 */
public class Test {

    public static void main(String args[]) {

        List<String> teamIndia = Arrays.asList("Virat", "Dhoni", "Jadeja");
        List<String> teamAustralia = Arrays.asList("Warner", "Watson", "Smith");
        List<String> teamEngland = Arrays.asList("Alex", "Bell", "Broad");
        List<String> teamNewZeland = Arrays.asList("Kane", "Nathan", "Vettori");
        List<String> teamSouthAfrica = Arrays.asList("AB", "Amla", "Faf");
        List<String> teamWestIndies = Arrays.asList("Sammy", "Gayle", "Narine");
        List<String> teamSriLanka = Arrays.asList("Mahela", "Sanga", "Dilshan");
        List<String> teamPakistan = Arrays.asList("Misbah", "Afridi", "Shehzad");
        
        List<List<String>> playersInWorldCup2016 = new ArrayList<>();
        playersInWorldCup2016.add(teamIndia);
        playersInWorldCup2016.add(teamAustralia);
        playersInWorldCup2016.add(teamEngland);
        playersInWorldCup2016.add(teamNewZeland);
        playersInWorldCup2016.add(teamSouthAfrica);
        playersInWorldCup2016.add(teamWestIndies);
        playersInWorldCup2016.add(teamSriLanka);
        playersInWorldCup2016.add(teamPakistan);
        
        // Let's print all players before Java 8
        List<String> listOfAllPlayers = new ArrayList<>();
        
        for(List<String> team : playersInWorldCup2016){
            for(String name : team){
                listOfAllPlayers.add(name);
            }
        }
        
        System.out.println("Players playing in world cup 2016");
        System.out.println(listOfAllPlayers);
        
        
        // Now let's do this in Java 8 using FlatMap
        List<String> flatMapList = playersInWorldCup2016
                                     .stream()
                                     .flatMap(pList -> pList.stream())
                                     .collect(Collectors.toList());
        
        System.out.println("List of all Players using Java 8");
        System.out.println(flatMapList);
    }

}

Output
run:
Players playing in world cup 2016
[Virat, Dhoni, Jadeja, Warner, Watson, Smith, Alex, Bell, Broad, Kane,
 Nathan, Vettori, AB, Amla, Faf, Sammy, Gayle, Narine, Mahela, Sanga, Dilshan,
 Misbah, Afridi, Shehzad]
List of all Players using Java 8
[Virat, Dhoni, Jadeja, Warner, Watson, Smith, Alex, Bell, Broad, Kane, Nathan,
 Vettori, AB, Amla, Faf, Sammy, Gayle, Narine, Mahela, Sanga, Dilshan, Misbah,
 Afridi, Shehzad]
BUILD SUCCESSFUL (total time: 0 seconds)

You can see that the final list contains all the elements from each list. So flatMap() is working fine to flatten a Stream of List of String into just a Stream of String, that's the true power of flat map operation in Java 8.


That's all about how to use the flatMap() function in Java 8.  Just remember the difference between map() and flatMap() in Java 8 and when to use the map() vs flatMap(). If you use a function that returns a list of values in map() operation you get a Stream of Stream and by using flatMap you can convert that to Stream of values.

In short, you can combine several small lists of values into a big list of values using flatMap(). It's called flatMap() because it flattens the Stream.


Related Java 8 Tutorials
If you are interested in learning more about the new features of Java 8, here are my earlier articles covering some of the important concepts of Java 8
  • Java 8 Interview Questions Preparation Course (free)
  • 5 Books to Learn Java 8 from Scratch (books)
  • What is the default method in Java 8? (example)
  • How to use Stream class in Java 8 (tutorial)
  • How to use filter() method in Java 8 (tutorial)
  • How to convert List to Map in Java 8 (solution)
  • Difference between abstract class and interface in Java 8? (answer)
  • How to use peek() method in Java 8 (example)
  • How to sort the may by values in Java 8? (example)
  • How to join String in Java 8 (example)
  • 5 Free Courses to learn Java 8 and 9 (courses)
  • How to sort the map by keys in Java 8? (example)
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • How to format/parse the date with LocalDateTime in Java 8? (tutorial)

Thanks for reading this article so far. If you like this Stream and FlatMap example then please share it with your friends and colleagues. If you have any questions or suggestions then please drop a comment.

P. S.: If you just want to learn more about new features in Java 8 then please see these free Java 8 Functional Programming courses on Udemy. It explains all the important features of Java 8 like Lambda expressions, streams, functional interfaces, Optional, new Date-Time API,  and other miscellaneous changes.

5 comments:

  1. > The result would be [[3,7],[23],[2,3,7]]. If you want to flat this stream of a stream into a stream of values,
    > you can use the flatMap() which will return [3,7,2,3,2,3,7].

    In your list, should the 2,3 be 23, meaning the list is [3,7,23,2,3,7]

    ReplyDelete
  2. Very nice explaination before this I was in confusion mode

    ReplyDelete
  3. instead of using lambda expression .flatMap(pList -> pList.stream()) we can use .flatMap(Collection::stream) ,looks neat

    ReplyDelete
  4. pList.stream() it's not working

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.