flatMap in Java
Flattening nested structures into one stream.
map + split + count() says 2. You wanted 5. What's the missing ingredient?Boxes inside boxes
If each element holds several values, map gives you a stream of containers โ one per input. **flatMap opens every container and pours its contents onto one flat belt.** map: one in โ one out. flatMap: one in โ zero or more out.
The rule: return a Stream
flatMap's function must return a Stream โ for lists, that's List::stream. flatMap then joins all those little streams into one. An empty inner list contributes nothing.
List<List<Integer>> nested = List.of(
List.of(1, 2), List.of(), List.of(3));
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.toList(); // [1, 2, 3]map vs flatMap
What does this print?
long a = Stream.of("hi", "yo")
.map(s -> s.split(""))
.count();
long b = Stream.of("hi", "yo")
.flatMap(s -> Arrays.stream(s.split("")))
.count();
System.out.println(a + " " + b);4 42 42 2
Show the answer
2 4 โ map turns each word into one array, so there are still 2 elements. flatMap streams each array's letters and merges them into 4.
Returning a List instead of a Stream
orders.stream()
.flatMap(Order::items) // a List!
.toList();items() returns a List, but flatMap requires a Stream. .flatMap(g -> g) on lists fails the same way.
orders.stream()
.flatMap(o -> o.items().stream())
.toList();Turn each inner list into a stream and you get one Stream<Item>. (map(Order::items) would give a Stream<List<Item>>.)
mapMulti: the imperative cousin
Java 16 added **mapMulti: instead of returning a stream, you push** zero or more results into a consumer. Handy when building a little stream per element feels heavy.
List<Integer> r = Stream.of(1, 2, 3)
.<Integer>mapMulti((n, out) -> {
if (n != 2) out.accept(n * 10);
})
.toList(); // [10, 30]Flattening is everywhere
APIs return nested data constantly: orders โ line items, users โ roles, files โ lines โ words. flatMap is how you get "all items across all orders" in one line โ and "use flatMap vs map" is a favourite interview question.
Key takeaways
- map: one element in โ one element out
- flatMap: one element in โ zero or more elements out
- The function must return a Stream, e.g. List::stream
- Java 16 added mapMulti as an imperative alternative
๐ก flatMap is like emptying several shopping bags onto one checkout belt.
flatMap isn't stream-specific jargon: Optional has a flatMap too, and the same idea powers flatMap in Scala, Kotlin, JavaScript and Rust.
Practice questions
What does this print?
List<List<Integer>> nested = List.of(
List.of(1, 2), List.of(3), List.of());
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.toList();
System.out.println(flat);- [[1, 2], [3], []]
- [1, 2, 3, []]
- [1, 2, 3]
- [3]
Check your answer
[1, 2, 3]. Each inner list becomes its own stream and flatMap concatenates them. The empty list contributes nothing.
What does this print?
long n = Stream.of("a b", "c d e")
.map(s -> s.split(" "))
.count();
long m = Stream.of("a b", "c d e")
.flatMap(s -> Arrays.stream(s.split(" ")))
.count();
System.out.println(n + " " + m);- 5 5
- 2 2
- 5 2
- 2 5
Check your answer
2 5. map turns each line into ONE array, so there are still 2 elements. flatMap streams each array's words and merges them into 5 elements.