Java 8 flatMap example

In Java 8, Stream can hold different data types, for examples:


Stream<String[]>	
Stream<Set<String>>	
Stream<List<String>>	
Stream<List<Object>>

But, the Stream operations (filter, sum, distinct…) and collectors do not support it, so, we need flatMap() to do the following conversion :


Stream<String[]>		-> flatMap ->	Stream<String>
Stream<Set<String>>	-> flatMap ->	Stream<String>
Stream<List<String>>	-> flatMap ->	Stream<String>
Stream<List<Object>>	-> flatMap ->	Stream<Object>

How flatMap() works :

{ {1,2}, {3,4}, {5,6} } -> flatMap -> {1,2,3,4,5,6}

{ {'a','b'}, {'c','d'}, {'e','f'} } -> flatMap -> {'a','b','c','d','e','f'}

1. Stream + String[] + flatMap

1.1 The below example will print an empty result, because filter() has no idea how to filter a stream of String[].

TestExample1.java

package com.mkyong.java8;

import java.util.Arrays;
import java.util.stream.Stream;

public class TestExample1 {

    public static void main(String[] args) {

        String[][] data = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};

        //Stream<String[]>
        Stream<String[]> temp = Arrays.stream(data);

        //filter a stream of string[], and return a string[]?
        Stream<String[]> stream = temp.filter(x -> "a".equals(x.toString()));

        stream.forEach(System.out::println);

    }

}

Output

//empty...

1.2 In above example, we should use flatMap() to convert Stream<String[]> to Stream<String>.

TestExample1.java

package com.mkyong.java8;

import java.util.Arrays;
import java.util.stream.Stream;

public class TestExample1 {

    public static void main(String[] args) {

        String[][] data = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};

        //Stream<String[]>
        Stream<String[]> temp = Arrays.stream(data);

        //Stream<String>, GOOD!
        Stream<String> stringStream = temp.flatMap(x -> Arrays.stream(x));

        Stream<String> stream = stringStream.filter(x -> "a".equals(x.toString()));

        stream.forEach(System.out::println);

		/*Stream<String> stream = Arrays.stream(data)
                .flatMap(x -> Arrays.stream(x))
                .filter(x -> "a".equals(x.toString()));*/

    }

}

Output

a

2. Stream + Set + flatMap

2.1 A student POJO.

Student.java

package com.mkyong.java8;

import java.util.HashSet;
import java.util.Set;

public class Student {

    private String name;
    private Set<String> book;

    public void addBook(String book) {
        if (this.book == null) {
            this.book = new HashSet<>();
        }
        this.book.add(book);
    }
    //getters and setters

}

2.2 flatMap() and Set example.

TestExample2.java

package com.mkyong.java8;

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

public class TestExample2 {

    public static void main(String[] args) {

        Student obj1 = new Student();
        obj1.setName("mkyong");
        obj1.addBook("Java 8 in Action");
        obj1.addBook("Spring Boot in Action");
        obj1.addBook("Effective Java (2nd Edition)");

        Student obj2 = new Student();
        obj2.setName("zilap");
        obj2.addBook("Learning Python, 5th Edition");
        obj2.addBook("Effective Java (2nd Edition)");

        List<Student> list = new ArrayList<>();
        list.add(obj1);
        list.add(obj2);

        List<String> collect =
                list.stream()
                        .map(x -> x.getBook())      //Stream<Set<String>>
                        .flatMap(x -> x.stream())   //Stream<String>
                        .distinct()
                        .collect(Collectors.toList());

        collect.forEach(x -> System.out.println(x));
    }

}

Output

Spring Boot in Action
Effective Java (2nd Edition)
Java 8 in Action
Learning Python, 5th Edition

Try comments the flatMap(x -> x.stream()) the Collectors.toList() will prompts a compiler error, because it has no idea how to collect a stream of Set object.

3. Stream + Primitive + flatMapToInt

3.1 For primitive type, you can use flatMapToInt.

TestExample3.java

package com.mkyong.java8;

import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class TestExample3 {

    public static void main(String[] args) {

        int[] intArray = {1, 2, 3, 4, 5, 6};

        //1. Stream<int[]>
        Stream<int[]> streamArray = Stream.of(intArray);

        //2. Stream<int[]> -> flatMap -> IntStream
        IntStream intStream = streamArray.flatMapToInt(x -> Arrays.stream(x));

        intStream.forEach(x -> System.out.println(x));

    }

}

Output

1
2
3
4
5
6

References

  1. Stream#flatMap JavaDoc
  2. Stackoverflow – Difference between map and flatMap methods in Java 8
  3. Java 8 – How to print an Array
  4. Java 8 – Collectors groupingBy and mapping example

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
Johny Rufus
Guest
Johny Rufus
Nice article, but I think there is a fundamental flaw in the way the flatmap concept is projected. For e.g as per the article “Stream -> flatMap -> Stream” But the correct way to look at flatMap is When you have a Stream and a transformation map function that takes each string and converts to a Stream then we get a resultant Stream<Stream>” because the mapping function for each string is something like (s -> Arrays.stream(s.split(“”))) To avoid the Stream<Stream>, we use flatmap , which flattens the individual streams to one single stream of Stream e.g. Stream stream = Stream.of(“abc”,… Read more »
Laxminarsaiah Ragi
Guest
Laxminarsaiah Ragi

public User getUserById(Integer uid) {
return (User) userList.stream().filter(user -> user.getId().equals(uid));
}

The above code giving java.util.stream.ReferencePipeline$2 cannot be cast to com.pi.user.User

How can i return Object(in my case User) by lamda

Laxminarsaiah Ragi
Guest
Laxminarsaiah Ragi

Hi Any one tell me this below one is correct?
public User getUserById(Integer uid) {
return userList.stream().filter(user1 -> user1.getId().equals(uid)).collect(Collectors.toList()).get(0);
}

Dilip
Guest
Dilip

In my requirements I want developer name concatenated with language.
Something like
esoteric-clojure
esoteric-scala
esoteric-groovy
esoteric-go

Need help

Dimuthu
Guest
Dimuthu

Simple as usual. Thanks.

satya alapati
Guest
satya alapati

what if you have a List and that object can be a list or objects themselves? like {“a”, {“b”, “c”}, “d”}

Romy
Guest
Romy

Thanks for your help, you explained the concept in a self explanatory way! :)

Carol
Guest
Carol

good article!

Ivan
Guest
Ivan

It helps me to learn more about java 8, thanks.

mkyong
Guest
mkyong

Thanks, typo error, fixed and updated.

Alo
Guest
Alo

{ {‘a’,’b’}, {‘c’,’d’}, {‘e’,’f’} } -> flatMap -> {‘a’,’b’,’c’,’d’,’b’,’b’,’b’} shouldn’t be

{ {‘a’,’b’}, {‘c’,’d’}, {‘e’,’f’} } -> flatMap -> {‘a’,’b’,’c’,’d’,’b’,’e’,’f’} ?

mkyong
Guest
mkyong

Typo error, fixed and updated, thanks.

Abhay
Guest
Abhay

Thank you so much and It is very helpful.