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
author image

mkyong

Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities. Read all published posts by

Comments

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 »

Minh
Guest
Minh

Thank you

Sami-Djo
Guest
Sami-Djo

Isn’t it rather :
Stream stream = Stream.of(“abc”, “def”, “ghi”);
Stream<Stream> s1 = stream.map(s -> Arrays.stream(s.split(“”)));
Stream s2 = stream.flatMap(s -> Arrays.stream(s.split(“”)));

Dimuthu
Guest
Dimuthu

Simple as usual. Thanks.

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.

mkyong
Guest
mkyong

Thanks, typo error, fixed and updated.

Ivan
Guest
Ivan

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

Carol
Guest
Carol

good article!

Romy
Guest
Romy

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

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”}

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

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);
}

Matheus Rambo
Guest
Matheus Rambo

userList.stream().filter(user1 -> user1.getId().equals(uid)).findFirst().orElseThrow(() -> new Exception(“Not Found”));

Abhay
Guest
Abhay

Thank you so much and It is very helpful.

Minh
Guest
Minh

Thank you for the article. There is one point I think you made a mistake:
In section 1.1 you said “The below example will print an empty result, because filter() has no idea how to filter a stream of String[].”
I don’t think that it’s because filter() has no idea how to filter a stream of String[].
Stream stream = temp.filter(x -> “a”.equals(x.toString()));
Here, x is a array of String. When we call x.toString(), the address of that array will be returned. “a” cannot be equals to that address, so “a”.equals(x.toString()) will returns false every time and results in an empty Stream.

Ankush Arora
Guest
Ankush Arora

List collect =
list.stream()
.map(x -> x.getBook()) //Stream<Set>
This will give Stream not Stream<Set>. So not an ideal example for flatMap method.