last modified May 24, 2025
This article demonstrates how to use the Java Stream flatMap method to transform and flatten nested data structures.
flatMap is an intermediate stream operation that maps each element to a stream and then flattens these streams into a single stream. It's particularly useful when working with nested collections or when each element can be transformed to multiple elements.
The method signature for flatMap is:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
The mapper function takes an element of type T and returns a Stream of R. The flatMap operation then concatenates all these streams into a single stream.
The most common use case for flatMap is flattening nested collections.
void main() {
List<List<String>> nestedLists = List.of(
List.of("a", "b", "c"),
List.of("d", "e"),
List.of("f", "g", "h", "i")
);
Stream<String> flattened = nestedLists.stream()
.flatMap(List::stream);
flattened.forEach(System.out::println);
}
This example takes a list of lists and flattens it into a single stream of strings. The List::stream method reference converts each inner list to a stream, and flatMap combines them.
flatMap can both transform elements and flatten the results.
void main() {
List<Integer> numbers = List.of(1, 2, 3, 4);
Stream<Integer> doubled = numbers.stream()
.flatMap(n -> Stream.of(n, n * 2));
doubled.forEach(System.out::println);
}
This example takes each number and maps it to a stream containing the original number and its double. The flatMap operation then combines all these streams.
flatMap is useful for filtering out empty Optionals while extracting values.
void main() {
List<Optional<String>> options = List.of(
Optional.of("apple"),
Optional.empty(),
Optional.of("banana"),
Optional.empty(),
Optional.of("cherry")
);
Stream<String> fruits = options.stream()
.flatMap(Optional::stream);
fruits.forEach(System.out::println);
}
This example filters out empty Optionals and extracts the values from present
ones. The Optional::stream method converts an Optional
to a stream of 0 or 1 elements.
flatMap can be used to split strings and combine all words into one stream.
void main() {
List<String> sentences = List.of(
"Hello there",
"Java streams are powerful",
"flatMap is useful"
);
Stream<String> words = sentences.stream()
.flatMap(s -> Stream.of(s.split(" ")));
words.forEach(System.out::println);
}
This example splits each sentence into words and combines all words from all sentences into a single stream. The lambda splits each string by spaces.
$ java Main.java Hello there Java streams are powerful flatMap is useful
flatMap is useful for extracting nested collections from objects.
record Order(String id, List<String> items) {
}
void main() {
List<Order> orders = List.of(
new Order("001", List.of("Shirt", "Pants")),
new Order("002", List.of("Shoes", "Socks", "Hat")),
new Order("003", List.of("Jacket"))
);
Stream<String> allItems = orders.stream()
.flatMap(order -> order.items().stream());
allItems.forEach(System.out::println);
}
This example extracts all items from all orders into a single stream. Each Order's items are converted to a stream and then flattened.
$ java Main.java Shirt Pants Shoes Socks Hat Jacket
flatpMap can combine elements from multiple sources.
void main() {
Stream<String> stream1 = Stream.of("A", "B", "C");
Stream<String> stream2 = Stream.of("X", "Y", "Z");
Stream<Stream<String>> nested = Stream.of(stream1, stream2);
Stream<String> combined = nested.flatMap(s -> s);
combined.forEach(System.out::println);
}
This example combines two separate streams into one using flatMap.
Note that once a stream is consumed (like in the flatMap operation), it can't be
reused.
flatMap can be used to generate Cartesian products of collections.
void main() {
List<String> colors = List.of("Red", "Green", "Blue");
List<String> sizes = List.of("S", "M", "L");
Stream<String> products = colors.stream()
.flatMap(color ->
sizes.stream()
.map(size -> color + " " + size)
);
products.forEach(System.out::println);
}
This example generates all possible combinations of colors and sizes. Each color is paired with each size using nested flatMap and map operations.
$ java Main.java Red S Red M Red L Green S Green M Green L Blue S Blue M Blue L
You can use flatMapToInt, flatMapToDouble, or
flatMapToLong to flatten and process collections of numbers. For
example, you can convert a list of strings representing numbers into a single
IntStream.
void main() {
List<String> numberStrings = List.of("1,2,3", "4,5", "6");
IntStream numbers = numberStrings.stream()
.flatMapToInt(s -> Arrays.stream(s.split(",")).mapToInt(Integer::parseInt));
numbers.forEach(System.out::println);
}
This example splits each string by commas, parses the numbers, and flattens them
into a single IntStream.
flatMap can be used to parse a list of CSV strings, extract fields, and flatten them into a single stream for further processing.
record User(String firstName, String lastName, int age) {
}
void main() {
List<String> csvRows = List.of("John,Doe,30", "Jane,Smith,25",
"Bob,Johnson,40");
Stream<User> users = csvRows.stream()
.map(row -> row.split(",")) // Split row
.map(fields -> new User(fields[0], fields[1],
Integer.parseInt(fields[2]))); // Convert to User
users.forEach(System.out::println);
}
The example demonstrates how to parse CSV data, where each row is split into
fields, and then each field is used to create a User object. The
flatMap method is not explicitly used here, but it can be applied if you want to
flatten nested structures or combine multiple streams of users.
Java Stream flatMap documentation
In this article we have explored the Java Stream flatMap method.
It's a powerful tool for working with nested data structures, combining multiple
streams, and transforming elements while flattening the results.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Java tutorials.