Java 8 flatMap stream operator

Date published30.07.2018Time to read2 minutes read

Let's see a simple example of Java 8 Stream::flatMap method found in the Stream API. Definition of flatMap in the API doc is:

Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.)

So - say we have a simple Java class named Developer:

package rs.dodalovic.streams.flap_map;

import java.util.List;

public class Developer {
    private final String name;
    private final List<String> programmingLanguages;

    public Developer(String name, List<String> programmingLanguages) {
        this.name = name;
        this.programmingLanguages = programmingLanguages;
    }

    public String getName() {
        return name;
    }

    public List<String> getProgrammingLanguages() {
        return programmingLanguages;
    }
}

Simple POJO contains the developer name, as well as list of programming languages programmer knows. Now, let's create some executable code to finally demo what we want:

package rs.dodalovic.streams.flap_map;

import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Arrays.asList;

public class FlatMapMain {

    private static final String JAVA = "Java";
    private static final String PHP = "Php";
    private static final String JAVASCRIPT = "Javascript";
    private static final String RUBY = "Ruby";
    private static final String SCALA = "Scala";
    private static final String PYTHON = "Python";
    private static final String CLOJURE = "Clojure";

    public static void main(String[] args) {

        final List<Developer> developers = asList(
                new Developer("John", asList(JAVA, PHP)),
                new Developer("Peter", asList(JAVA, PHP, JAVASCRIPT)),
                new Developer("Mike", asList(JAVA, PHP, CLOJURE)),
                new Developer("Steven", asList(JAVA, PHP, JAVASCRIPT, PYTHON)),
                new Developer("Kylie", asList(PHP, RUBY, SCALA)));

        final Set<String> supportedProgrammingLanguages = developers.stream()
                .flatMap(toLanguagesStream())
                .collect(Collectors.toSet());

        System.out.format("All supported languages: \n\n");
        supportedProgrammingLanguages.forEach(System.out::println);
    }

    private static Function<Developer, Stream<String>> toLanguagesStream() {
        return developer -> developer.getProgrammingLanguages().stream();
    }
}

First, we populate developers List with some sample developers. What we do after is that we start streaming through given developers, and then want to collect all the languages that all given developers support in total. We do that using flatMap operator which accepts mapping Function parameter. In our case we implemented the mapping in toLanguagesStream method, where we map each developer to it's supported languages stream. What happens then is that for each developer we get it's languages, which are merged at the end - after last developer is streamed. Java Stream API will do the merging for us, so flatMap returns final stream - consisting of all merged languages for all the developers.

In order to display only distinct languages (since we have the cases one language is shared across many developers) we use collect operator, which accepts instance of Collector interface. In our case we choose out of the box implementation which is shipped with JDK - Collectors.toSet().

Code snippets can be seen here

Feel free to experiment with flatMap and find other useful cases to apply it.

That was all for today! Hope you liked it!