The Difference Between map() and flatMap()

1. Overview

map() and flatMap() APIs stem from functional languages. In Java 8, we can find them in Optional, Stream and in CompletableFuture (although under a slightly different name).

Streams represent a sequence of objects whereas optionals are classes that represent a value that can be present or absent. Among other aggregate operations, we have the map() and flatMap() methods.

Despite the fact that both have the same return types, they are quite different. Let’s explain these differences by analyzing some examples of streams and optionals.

2. Map and Flatmap in Optionals

The map() method works well with Optional — if the function returns the exact type we need:

Optional<String> s = Optional.of("test");
assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));

However, in more complex cases we might be given a function that returns an Optional too. In such cases using map() would lead to a nested structure, as the map() implementation does an additional wrapping internally.

Let’s see another example to get a better understanding of this situation:

assertEquals(Optional.of(Optional.of("STRING")), 
  Optional
  .of("string")
  .map(s -> Optional.of("STRING")));

As we can see, we end up with the nested structure Optional<Optional<String>>. Although it works, it’s pretty cumbersome to use and does not provide any additional null safety, so it is better to keep a flat structure.

That’s exactly what flatMap() helps us to do:

assertEquals(Optional.of("STRING"), Optional
  .of("string")
  .flatMap(s -> Optional.of("STRING")));

3. Map and Flatmap in Streams

Both methods work similarly for Optional.

The map() method wraps the underlying sequence in a Stream instance, whereas the flatMap() method allows avoiding nested Stream<Stream<R>> structure.

Here, map() produces a Stream consisting of the results of applying the toUpperCase() method to the elements of the input Stream:

List<String> myList = Stream.of("a", "b")
  .map(String::toUpperCase)
  .collect(Collectors.toList());
assertEquals(asList("A", "B"), myList);

map() works pretty well in such a simple case. But what if we have something more complex, such as a list of lists as an input?

Let’s see how it works:

List<List<String>> list = Arrays.asList(
  Arrays.asList("a"),
  Arrays.asList("b"));
System.out.println(list);

This snippet prints a list of lists [[a], [b]].

Now let’s use a flatMap():

System.out.println(list
  .stream()
  .flatMap(Collection::stream)
  .collect(Collectors.toList()));

The result of such a snippet will be flattened to [a, b].

The flatMap() method first flattens the input Stream of Streams to a Stream of Strings. Thereafter, it works similarly to the map() method.

4. Conclusion

Java 8 gives us the opportunity to use the map() and flatMap() methods that originally were used in functional languages.

We can invoke them on Streams and Optionals. These methods help us to get mapped objects by applying the provided mapping function.

As always, the examples in this article are available over on GitHub.

Related posts:

Java Program to Find Hamiltonian Cycle in an UnWeighted Graph
Spring Boot with Multiple SQL Import Files
An Intro to Spring Cloud Vault
Java Program to Apply Above-Below-on Test to Find the Position of a Point with respect to a Line
Java Program to Perform String Matching Using String Library
Java Web Services – Jersey JAX-RS – REST và sử dụng REST API testing tools với Postman
Java Program to Perform Naive String Matching
Guide to Character Encoding
Wiring in Spring: @Autowired, @Resource and @Inject
HandlerAdapters in Spring MVC
Ép kiểu trong Java (Type casting)
Java Program to Represent Linear Equations in Matrix Form
Java Program to Perform integer Partition for a Specific Case
Java Program to Implement Gale Shapley Algorithm
Exploring the Spring 5 WebFlux URL Matching
Quick Guide on Loading Initial Data with Spring Boot
Java Program to Perform Finite State Automaton based Search
Generating Random Dates in Java
Java Program to Find Minimum Number of Edges to Cut to make the Graph Disconnected
Java Program to Implement Knight’s Tour Problem
Giới thiệu thư viện Apache Commons Chain
Split a String in Java
Java Program to Implement Wagner and Fisher Algorithm for online String Matching
Câu lệnh điều khiển vòng lặp trong Java (break, continue)
Getting Started with GraphQL and Spring Boot
Adding Parameters to HttpClient Requests
Connect through a Proxy
Deploy a Spring Boot WAR into a Tomcat Server
Java Program to Implement the Vigenere Cypher
Java toString() Method
Java Program to Implement Sorting of Less than 100 Numbers in O(n) Complexity
Generic Constructors in Java