Map() vs flatMap() - What’s the Difference?

Learn via video course
FREE
View all courses
Java Course - Mastering the Fundamentals
Java Course - Mastering the Fundamentals
by Tarun Luthra
1000
5
Start Learning
Java Course - Mastering the Fundamentals
Java Course - Mastering the Fundamentals
by Tarun Luthra
1000
5
Start Learning
Topics Covered

Introduction

Both map() function in python and flatMap() in python are originated from Functional Programming. These are the functional operations. Since Java 8, you can find them in java.util.Optional class and java.util.stream.Stream interface.

Options are used to represent values that are either present or absent and are mostly used for avoiding null-checks. Streams are used to represent a sequence of values and perform various operations on them.

map() and flatMap() in Stream and Optional

Both methods have the same return type, yet the two differ. The most evident point about map vs flatmap is that when you use map(), it will transform each value inside Stream or Optional (if present) into some other value. Next, it would convert it into Stream or wrap it inside Optional, depending on where you use it.

For example, if you have Stream<String> (stream of strings) and map each string to an integer (through some Function given inside map), Stream<Integer> (stream of integers) is obtained. The map always transforms into a single value, i.e., establishes a one-to-one mapping between the input and output value.

Therefore, if the map used a function that transformed each string to Stream<Integer>, instead of just an integer, the result would be a nested stream or stream of streams, i.e., Stream<Stream<Integer>> as the transformed value is taken as a single value. To tackle such nested structures, use flatMap to map and flatten the nested collection or stream. flatMap is a combination of transformation and flattening. Hence, it uses one-to-many mapping.

In the case of optionals, flatMap will flatten a nested structure like <Optional<Optional<T>> to Optional<T>.

Note: Flattening is the process of converting several collections of items present inside another collection into a single collection of items. For example, [[1, 2], 3, [4, 5], []] is flattened to [1, 2, 3, 4, 5].

map() method

Syntax

For Stream

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

  • R -- Element type of new Stream
  • T -- Type of stream elements
  • mapper -- a non-interfering, stateless function to apply to each element

For Optional

<U> Optional<U> map(Function<? super T,? extends U> mapper)

  • U -- Type of the result of the mapping function
  • T -- Type of the element stored in Optional which is to be mapped
  • mapper -- A mapping function to apply to the value, if present

Usage and Example

  1. Use map() for mapping an input element to a unique output element. For example, mapping each string in a list to its length.
  2. Use it when there is a one-to-one mapping requirement. For example, get the date of birth from a given Employee object.

Description

map() is used just for the transformation of an input to some output value.

  1. map() is an intermediate operation. Returns another Stream or Optional.
  2. map() operation takes a Function (a functional interface) that is called for each input value in the case of Stream. In the case of Optional, it maps the value and returns an optional describing the value or an empty optional based on the presence of value.
  3. The mapper function used for transformation is stateless (does not store the information of previously processed objects) and returns only a single value.
  4. Use map() to convert one Stream or Optional to another Stream or Optional.
  5. The mapped stream is closed after its contents have been placed into the new output stream.
  6. It does not flatten the stream or is optional.

flatMap() Method

Syntax

For Stream

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

  • R -- Element type of new Stream
  • T -- Type of stream elements
  • mapper -- a non-interfering, stateless function to apply to each element which produces a stream of new values

For Optional

<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

  • U -- The type parameter to the Optional, also the type of value returned after mapping
  • T -- Type of the element stored in Optional which is to be mapped
  • mapper -- A mapping function to apply to the value, if present

Usage and Example

  1. flatMap() is used when you want to map a single input value to zero or more output values.
  2. Go with it when there is a one-to-many mapping requirement. For example, finding phone numbers from a given list of customers. You can have customers that have more than one phone number.
  3. You can also use it to flatten the obtained collection of collections or to avoid nested optional structures.

Description

flatMap() is combination of a map() and a flattening operation. However, the difference between map and flatmap is that flatmap() maps one input value multiple output values while map() maps to one value.

  1. flatMap() is an intermediate operation and return a new Stream or Optional.
  2. It also takes a Function to map value(s) and returns values similar to map().
  3. The mapper function used for transformation in flatMap() is stateless and returns a stream of new values in case of streams or another optional in case of optionals.
  4. Each mapped stream is closed after placing contents on new stream.
  5. It performs an extra step of flattening as opposed to map().

map vs flatMap

The main difference between map and flatMap is their processing approach: map handles a stream of values with a one-to-one mapping, whereas flatMap processes a stream of streams, enabling a one-to-many mapping. Essentially, map transforms data, while flatMap both maps and flattens, converting nested data structures into a single flat stream.

map() methodflatMap() method
It processes a stream of values.It processes a stream of streams of values.
The function passed to the map() operation returns a single value for a single input.The function you pass to the flatMap() operation returns an arbitrary number of values (zero or more) as output for a single value.
One-to-one mapping occurs.One-to-many mapping occurs.
It only performs the mapping.It performs both mapping and flattening.
It transforms Stream<T> to Stream<R> or Optional<T> to Optional<R>.It performs the mapping functionality and converts Stream<Stream<T>> to Stream<T> or Optional<Optional<T>> to Optional<T>.
Example: List<Integer> stringLengths = Stream.of("ab", "abcd", "abc").map(String::length).collect(Collectors.toList());Example: List<Integer> allDistinctNums = Stream.of(evens, odds, primes).flatMap(numList -> numList.stream()).distinct().collect(Collectors.toList());

T: Type of the input value, R: Type of the output value

map() and flatMap() in Optionals

Transform values using map()

Output:

Optional[THIS IS A TEST STRING]
Optional.empty

Explanation:

The first optional object created contains a string value in it so the map() method will map that value using string's toUpperCase(). This method will return a string which is then wrapped into optional due to map(). But for the second optional, which contains no value in it, the map will return another empty optional.

Avoid nesting of Optionals using flatMap()

Consider having a school bag which may or may not contain a lunch box and that lunch box may or may not contain food items.

Output:

Explanation: Note in the above code that each getter method returns an Optional object. So, using a map() method on optional school bag objects (schoolBag1, schoolBag2 & schoolBag3) to get the LunchBox optional object will not work as this will give a nested optional object which is Optional<Optional<LunchBox>. Due to this, we would not be able to call another map() method to get foodItems from the lunch box.

The flatMap method can easily tackle this problem. In printFoodItems, the first call to flatMap() on the optional school bag object will return an Optional<LunchBox>. The second call to flatMap() returns an Optional<List<String>>. The orElse() is used to assign a default value if there's an empty optional.

The example shows how the flatMap() transforms and flattens the optionals, and also explains the difference between map and flatmap in Java 8 Optionals.

map() and flatMap in Streams

To understand map vs flatmap for Streams you can consider the following given examples:

Get length of all the strings in a list using map()

Output:

Explanation:

Firstly, we generate a stream out of the list of strings. The length() string method maps the values of this stream to integers. This method is given as a mapping function to map() in the form of method reference. Finally, we collect the values of the resulting stream into a list through the utility method toList() present in Collectors.

Flatten a list of list of integers using flatMap()

Output:

Explanation:

In the above example, we create three lists of numbers: evens, odds, and primes. We then generate a list of lists using previously created number lists using Arrays.asList(). It forms a nested list of numbers. The flatMap uses the stream of this list of nested lists (listOfListOfNumbers) for transforming each of the nested lists into a stream. It next flattens them to produce another stream of integers. The distinct() (another intermediate method) takes in the stream returned by flatMap and gives another stream containing unique numbers. Finally, we collect the stream of values in a list as done in the previous example.

The example also helps in understanding the map vs flatmap concept.

Explore Scaler Topics Python Tutorial and enhance your Python skills with Reading Tracks and Challenges.

Conclusion

  1. map() vs flatMap() is an important concept in Java 8 that helps in understanding functional programming operations.
  2. map() and flatMap() in Streams help apply programming logic in a functional manner.
  3. map() and flatMap() in Optionals help in dealing effectively with null values and avoid NullPointerException.
  4. map() is used only for transformation of a stream of values or values in optionals. Each value is mapped to a unique value that may be a list or some other value.
  5. flatMap() is a combination of map() and a flattening operation. It combines the transformation of values and flattens the resulting stream of values or stream of streams into a single stream that only consists of a single list storing values. A similar operation is carried out for Optionals to avoid nested structures.
  6. The mapping function of map() should be one-to-one, meaning each input value is mapped to a single output value.
  7. The mapping function of flatMap() should be one-to-many, meaning each input value can be mapped to multiple output values or even an empty stream or optional.
  8. When using map(), the resulting stream or optional will always have the same number of elements as the original. Each element is transformed individually, resulting in a one-to-one mapping between input and output elements.
  9. In contrast, flatMap() allows for the transformation of each element to multiple elements or even an empty stream or optional. It provides a mechanism for one-to-many mapping and also handles the flattening of nested collections or optional.

Learn More