Understanding Java Stream map() vs flatMap() with Practical Code Samples

This article explains the functional differences between Java Stream's map() and flatMap() methods, demonstrates their behavior with simple and nested list examples, and clarifies how each transforms or flattens data in Java 8 streams.

FunTester
FunTester
FunTester
Understanding Java Stream map() vs flatMap() with Practical Code Samples

Overview

The Java Stream API provides two frequently used intermediate operations, map() and flatMap(). Both accept a function and return a new Stream, but they differ in how many output elements each input element can produce.

Simple forEach demo

List<String> funs = Arrays.asList("F", "U", "N");
funs.stream().forEach(x -> output(x));

This prints each element on a separate line.

map() – one‑to‑one transformation

map()

is an intermediate operation that applies a function to each element and returns exactly one result per input.

Append a suffix to each string:

List<String> funs = Arrays.asList("F", "U", "N");
funs.stream()
    .map(x -> x + "001")
    .forEach(x -> output(x));
// Output: F001 U001 N001

Working with a nested collection:

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nested = Arrays.asList(fun1, fun2);

// map returns a Stream of Streams
nested.stream()
    .map(list -> list.stream().map(String::toUpperCase))
    .forEach(innerStream -> output(innerStream));

The forEach prints the Stream objects themselves because map() produced a Stream<Stream<String>>. To obtain the actual strings, the inner stream must be iterated or flattened:

nested.stream()
    .map(list -> list.stream().map(String::toUpperCase))
    .forEach(inner -> inner.forEach(s -> output(s)));
// Prints ONE TWO THREE FOUR FIVE SIX

flatMap() – flattening nested streams

flatMap()

also receives a function, but the function must return a Stream. The resulting streams are merged into a single stream, effectively flattening the hierarchy.

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nested = Arrays.asList(fun1, fun2);

nested.stream()
    .flatMap(list -> list.stream())   // flatten List<String> to Stream<String>
    .map(String::toUpperCase)
    .forEach(x -> output(x));
// Output: ONE TWO THREE FOUR FIVE SIX

Javadoc signature:

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

Key differences

Cardinality : map() produces exactly one output element for each input element. flatMap() can produce zero, one, or many output elements per input, because it concatenates the streams returned by the mapper.

Use case : Use map() when the transformation result is a single value (e.g., converting a string to uppercase). Use flatMap() when each input maps to a collection or another stream that should be processed as a single continuous stream (e.g., flattening a List<List<String>>).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavafunctional programmingMAPjava8Stream APIflatMap
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.