Stream flatMap in Java

Naveen AnamaneniUpdated · 4 min read

The flatMap method in Java streams is used to turn each element into a stream of zero or more elements and then join all those small streams into one flat stream. It is the tool for "nested" data: a list of lists, sentences made of words, or students who each have several subjects. Where map gives exactly one output per input, flatMap can give many or none. In this lesson, you will learn how flatMap works and how it differs from map.

Declaration

Declaration
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

The function must return a stream for each element.

map keeps the nesting; flatMap pours the inner elements into one stream

Example: Flattening a List of Lists

Let's see an example where two classes each have a list of students.

Flatten.java▶ Try it
import java.util.List;
 
public class Flatten {
    public static void main(String[] args) {
        List<List<String>> classes = List.of(
            List.of("Navika", "Srihitha"),
            List.of("Advitha"),
            List.of());
 
        List<String> everyone = classes.stream()
            .flatMap(List::stream)
            .toList();
        System.out.println(everyone);
 
        long nested = classes.stream().map(List::stream).count();
        System.out.println("With map: " + nested + " streams");
    }
}
Output
[Navika, Srihitha, Advitha]
With map: 3 streams

Explanation: flatMap(List::stream) turns each inner list into a stream and joins them, so the result is one list of three names. The empty third class adds nothing. With map, the result would be a stream of 3 streams, still nested.

Example: Splitting Sentences into Words

Words.java▶ Try it
import java.util.Arrays;
import java.util.List;
 
public class Words {
    public static void main(String[] args) {
        List<String> lines = List.of("java is fun", "streams are fun");
 
        List<String> words = lines.stream()
            .flatMap(line -> Arrays.stream(line.split(" ")))
            .distinct()
            .sorted()
            .toList();
        System.out.println(words);
    }
}
Output
[are, fun, is, java, streams]

Explanation: Each line is split into an array of words, which Arrays.stream turns into a stream. flatMap joins the words of both lines, and distinct removes the repeated "fun".

Example: Nested Objects

Subjects.java▶ Try it
import java.util.List;
 
public class Subjects {
    record Student(String name, List<String> subjects) { }
 
    public static void main(String[] args) {
        List<Student> students = List.of(
            new Student("Navika", List.of("Java", "SQL")),
            new Student("Srihitha", List.of("Java", "Python")),
            new Student("Advitha", List.of("C")));
 
        System.out.println(students.stream()
            .flatMap(s -> s.subjects().stream())
            .distinct()
            .toList());
 
        System.out.println(students.stream()
            .flatMap(s -> s.subjects().stream()
                           .map(sub -> s.name() + ":" + sub))
            .toList());
    }
}
Output
[Java, SQL, Python, C]
[Navika:Java, Navika:SQL, Srihitha:Java, Srihitha:Python, Advitha:C]

Explanation: The first pipeline lists every subject anyone takes, once each. The second pairs each student with each of their subjects, using a map inside the flatMap.

Common Mistakes

Using map with a function that returns a stream or list. You get Stream<Stream<T>> or Stream<List<T>>; use flatMap.

Returning null from the flatMap function. Return Stream.empty() instead (a null is treated as empty, but it's unclear).

Forgetting Arrays.stream around split. split returns an array, not a stream.

Interview Corner

What is the difference between map and flatMap?

map applies a function that returns one value per element, so the stream keeps the same number of elements, possibly of a new type. flatMap applies a function that returns a stream per element and then flattens all those streams into a single stream, so each input can produce zero, one or many outputs. flatMap is used to flatten nested structures, such as a list of lists or lines of words.

Practice

  1. Easy: Given a List<List<Integer>>, compute the total of all the numbers with flatMap and mapToInt.
  2. Harder: Given a list of sentences, count how many times each letter appears across all of them, using flatMap over chars().

Quick check: flatMap

4 questions
1What must the flatMap function return?
2What does map(List::stream) produce from a Stream<List>?
3Can flatMap produce zero elements from one input?
4Which is a good use of flatMap?

Key Takeaways

Was this tutorial helpful?

Lesson 318 of 482