Java 8 introduced the Stream API, which brought a powerful way to process collections using a functional programming style. Two of the most frequently used methods in this API are map()
and flatMap()
.
At first glance, both seem similar — they transform data. But their behavior differs when it comes to dealing with nested structures like List<List<T>>
.
In this article, we'll explore the key differences between map()
and flatMap()
using simple explanations, a comparison table, and complete examples with output.
📘 Quick Summary: map()
vs flatMap()
Feature | map() |
flatMap() |
---|---|---|
Processes | Stream of values | Stream of stream of values |
Functionality | Only mapping | Performs mapping + flattening |
Mapper Output | Produces a single value per input | Produces multiple values per input |
Mapping Type | One-to-One mapping | One-to-Many mapping |
Data Transformation | Stream<T> → Stream<R> |
Stream<Stream<T>> → Stream<R> |
When to Use | When mapper produces single output per input | When mapper produces multiple outputs per input |
Let’s go deeper into each of these differences with examples and real output.
✅ What is map()
in Java Stream?
The map()
method is used to transform each element of the stream using a mapping function. It applies a function to each value and returns a new stream consisting of the results.
🔧 Syntax:
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
👨💻 Example Using map()
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Amit", "Sneha", "Ravi");
List<Integer> nameLengths = names.stream()
.map(String::length) // One-to-one transformation
.collect(Collectors.toList());
System.out.println(nameLengths); // Output: [4, 5, 4]
}
}
🧠 Explanation:
- Input stream:
"Amit"
,"Sneha"
,"Ravi"
- Output stream:
4
,5
,4
(length of each name) - Each input gives exactly one output → One-to-one mapping.
✅ What is flatMap()
in Java Stream?
The flatMap()
method is used when each element of the stream is mapped to a stream of values, and you want to flatten all nested streams into a single stream.
🔧 Syntax:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
👨💻 Example Using flatMap()
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMapExample {
public static void main(String[] args) {
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("Amit", "Ankit"),
Arrays.asList("Sneha", "Sonia"),
Arrays.asList("Ravi", "Ramesh")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream) // Flattens nested structure
.collect(Collectors.toList());
System.out.println(flatList); // Output: [Amit, Ankit, Sneha, Sonia, Ravi, Ramesh]
}
}
Explanation:
- Each
List<String>
becomes a stream. flatMap()
flattens all these small streams into a single stream.- Output: a flat list of all names.
- Each input list can contribute multiple values → One-to-many mapping.
⚖️ Difference Explained With Visual Structure
Let’s visualize the difference with structure transformation:
🟦 map()
Example:
List<List<String>> → Stream<List<String>> → List<Stream<String>> (Still nested)
🟩 flatMap()
Example:
List<List<String>> → Stream<List<String>> → flatMap → Stream<String> → List<String> (Flat)
So with map()
, if the mapper function returns a list, you end up with a list of lists. But with flatMap()
, you get a flat list.
✅ Use Cases for map()
vs flatMap()
Use map()
when:
- You’re transforming each element individually.
- You get exactly one value back per input.
List<String> names = Arrays.asList("Anil", "Reema", "Kiran");
List<String> upper = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// Output: [ANIL, REEMA, KIRAN]
Use flatMap()
when:
- Each input might return multiple values (like a list or stream).
- You want to flatten nested data structures.
List<String> phrases = Arrays.asList("Java 8", "Stream API", "flatMap explained");
List<String> words = phrases.stream()
.flatMap(s -> Arrays.stream(s.split(" ")))
.collect(Collectors.toList());
// Output: [Java, 8, Stream, API, flatMap, explained]
🧪 Testing the Behavior Side-by-Side
List<String> sentences = Arrays.asList("Hello World", "Java Stream", "flatMap vs map");
// Using map()
List<String[]> mapped = sentences.stream()
.map(s -> s.split(" "))
.collect(Collectors.toList());
// Using flatMap()
List<String> flatMapped = sentences.stream()
.flatMap(s -> Arrays.stream(s.split(" ")))
.collect(Collectors.toList());
System.out.println("Mapped Size: " + mapped.size()); // Output: 3 (List of arrays)
System.out.println("FlatMapped Size: " + flatMapped.size()); // Output: 6 (All words)
🧾 Summary Table Revisited
Feature | map() |
flatMap() |
---|---|---|
Processes | Stream of values | Stream of stream of values |
Functionality | Only mapping | Mapping + flattening |
Mapper Output | One value per input | Multiple values per input |
Mapping Type | One-to-One | One-to-Many |
Transformation | Stream<T> → Stream<R> |
Stream<Stream<T>> → Stream<R> |
Use When | Each input maps to a single result | Each input maps to a list or stream of results |
Example | List<String> → uppercase list |
List<List<String>> → flat list of strings |
Final Thoughts
Both map()
and flatMap()
are essential tools in the Java Stream toolbox. While map()
is perfect for straightforward transformations, flatMap()
shines when you're dealing with nested data structures or multiple values per element.
- Use
map()
when you know you're doing one-to-one conversions. - Use
flatMap()
when each input element may return multiple values (e.g., splitting, nested lists, complex structures).
Understanding the difference between these two helps you write cleaner, more efficient, and more expressive Java code.
Comments
Post a Comment
Leave Comment