Java 8 map() and flatMap() operations can be applied to either Streams or Optional.
Stream<T> can be thought of as a wrapper holding a sequence of objects of type T to help us operate over them.
Similarly, Optional<T> in Java 8 adds a layer to the top of element T, to help us determine if it exists or not. This helps in reducing null pointer checks to large extents, leading to a cleaner code.
In this tutorial, we’ll look at the usages of the map() and flatMap() for both scenarios and will cover the difference between them.
Java 8 flatMap() can be thought of as:
flatMap = flattening + map
To understand things better, let’s further breakdown our learning:
As we know map() method accepts a type T1 and transforms it into another type T2:
Optional<String> intStr = Optional.of("23"); Optional<Integer> intValue = intStr.map(Integer::parseInt);
But what if the function we have returns an Optional<T> instead of T. How to deal with it?
Let’s see an example of that as well:
//works just fine Optional<String> intStr = Optional.of("23"); Optional<Optional<Integer>> intValue = intStr.map(str -> Optional.of(Integer.parseInt(str));
Here the flatMap() method comes to our rescue making it look cleaner for us:
Optional<String> intStr = Optional.of("23"); Optional<Integer> intValue = intStr.flatMap(str -> Optional.of(Integer.parseInt(str)));
Let’s look at both map() and flatMap() declarations for Streams, as defined in JavaDoc:
<R> Stream<R> map(Function<? super T, ? extends R> mapper) <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
Let’s understand it further with an example.
Let’s first consider using a map() with Streams:
List<Integer> listOfIntegers = Arrays.asList("5", "10", "15", "20") .stream() .map(Integer::parseInt) .collect(Collectors.toList());
On the other hand, we might feel the need of using flatMap() when working with a stream of streams. For eg: when opening a stream over a List<List<String>>:
List<String> listOfIntegers = Arrays.asList(Arrays.asList("5", "10"), Arrays.asList("15", "20")) .stream() .flatMap(List::stream) .collect(Collectors.toList());
|Java 8 map()||Java 8 flatMap()|
|Accepts a function returning a single value.||Accepts a function returning stream of values eg: List.stream(), Array.stream() etc or Optional
|Transforms each element from type T to R.||flatMap involves flattening and mapping operation.
All streams generated by mapper function later gets flattened to a single stream.
In this tutorial, we looked at the differences between map() and flatMap() operation when working with Java 8 Streams and Optional. By now, we understand the usages of these two methods and the differences between them.