Published: December 20, 2016
Introduction
Java 8 introduced the powerful Streams API to simplify data processing tasks, making it easier to work with collections in a functional way. One of the key enhancements to the Streams API is the flatMap()
method, which allows you to flatten nested data structures into a single stream.
In this tutorial, we will cover:
- What
flatMap()
is and how it works. - How to use
flatMap()
to process nested data structures. - Real-world examples that demonstrate how
flatMap()
can simplify your code.
What is flatMap()?
The flatMap()
method is used to transform each element of a stream into another stream and then flatten all of those streams into a single stream. Essentially, it is used when you have nested collections (e.g., lists of lists) and want to “flatten” them into a single stream of elements.
While the map()
method transforms elements in a stream one-to-one (one element becomes one element), the flatMap()
method transforms each element into zero or more elements, and the resulting streams are merged into one.
Basic Usage of flatMap()
Let’s look at a simple example where we have a list of lists and we want to flatten it into a single stream of items.
Example: Flattening a List of Lists
import java.util.*;
import java.util.stream.*;
public class FlatMapExample {
public static void main(String[] args) {
// List of Lists
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("Java", "Python", "C++"),
Arrays.asList("JavaScript", "Ruby"),
Arrays.asList("Go", "Swift", "Kotlin")
);
// Using flatMap to flatten the list of lists
List<String> flattenedList = listOfLists.stream()
.flatMap(List::stream) // Flatten each inner list
.collect(Collectors.toList());
System.out.println(flattenedList);
}
}
Explanation:
- We have a list of lists of programming languages.
- We use the
flatMap()
method to flatten these lists into a single stream. - The
List::stream
method reference is used to convert each list into a stream, andflatMap()
flattens all these streams into one.
Output:
[Java, Python, C++, JavaScript, Ruby, Go, Swift, Kotlin]
Using flatMap() with Other Collections
flatMap()
can also be used with other types of collections like Set
or Map
, and it allows you to process the elements in a similar fashion.
Example: Flattening a Map of Lists
Let’s consider a map where each key is associated with a list of values. We’ll use flatMap()
to flatten this structure.
import java.util.*;
import java.util.stream.*;
public class FlatMapExample {
public static void main(String[] args) {
// Map with lists of values
Map<String, List<String>> map = new HashMap<>();
map.put("Fruit", Arrays.asList("Apple", "Banana", "Orange"));
map.put("Vegetable", Arrays.asList("Carrot", "Potato", "Spinach"));
// Flatten the map values using flatMap
List<String> flattenedList = map.values().stream()
.flatMap(List::stream) // Flatten each list in the map values
.collect(Collectors.toList());
System.out.println(flattenedList);
}
}
Explanation:
- We have a map where each value is a list of strings (e.g., fruits and vegetables).
- We use
flatMap()
to flatten these lists of values into a single stream of items.
Output:
[Apple, Banana, Orange, Carrot, Potato, Spinach]
When to Use flatMap()
flatMap()
is especially useful when you need to:
- Transform a collection of collections into a single collection.
- Flatten nested data structures.
- Merge multiple streams into one.
Here are some common scenarios where flatMap()
can be useful:
- Processing a list of lists, such as combining multiple user-generated lists of items.
- Combining streams from multiple sources, like reading multiple files into a single stream.
- Transforming complex hierarchical data into simpler, flat structures.
Chaining flatMap() with Other Stream Operations
Just like map()
, flatMap()
can be combined with other stream operations such as filter()
, reduce()
, or collect()
to build more complex queries.
Example: Filtering and Flattening Data
Let’s say we have a list of users, where each user has a list of books they own. We want to extract the titles of all books from all users, but only the books with more than 100 pages.
import java.util.*;
import java.util.stream.*;
public class FlatMapExample {
public static void main(String[] args) {
// Sample User class with list of books
class User {
String name;
List<Book> books;
User(String name, List<Book> books) {
this.name = name;
this.books = books;
}
}
class Book {
String title;
int pages;
Book(String title, int pages) {
this.title = title;
this.pages = pages;
}
}
// Sample users and books data
List<User> users = Arrays.asList(
new User("Alice", Arrays.asList(new Book("Java Basics", 150), new Book("Python Cookbook", 120))),
new User("Bob", Arrays.asList(new Book("Advanced Java", 200), new Book("C Programming", 80))),
new User("Charlie", Arrays.asList(new Book("Java in Depth", 300), new Book("Scala for the Brave", 150)))
);
// Flatten and filter books with more than 100 pages
List<String> bookTitles = users.stream()
.flatMap(user -> user.books.stream()) // Flatten the list of books
.filter(book -> book.pages > 100) // Filter books with more than 100 pages
.map(book -> book.title) // Map to book titles
.collect(Collectors.toList());
System.out.println(bookTitles);
}
}
Explanation:
- We have a list of users, and each user has a list of books.
- We use
flatMap()
to flatten the list of books. - We then filter the books to keep only those with more than 100 pages.
- Finally, we extract the book titles and collect them into a list.
Output:
[Java Basics, Python Cookbook, Advanced Java, Java in Depth, Scala for the Brave]
Conclusion
The flatMap()
method is a powerful tool in Java 8’s Streams API, allowing you to flatten nested collections and perform complex operations on them in a functional style. It is especially useful when working with hierarchical or nested data structures, enabling you to transform them into a simpler, flat structure.
In this tutorial, we covered:
- The basic usage of
flatMap()
. - How to flatten nested collections like lists and maps.
- How to chain
flatMap()
with other stream operations likefilter()
andmap()
.
Next, we will look into practical examples of how to use flatMap() in real-world applications.