map and flatmap in Java8
Map
- Is a not terminal operation i.e intermediate stream operation
- Takes a function and is called for every value in the input stream
- Returns one output value for every input value
- Returns Stream<R> type
- Syntax
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
- Usage Example : Adding a constant number to all elements in the list and returning the stream
FlatMap
- Is a non terminal operation i.e intermediate stream operation
- Takes a function and is called for every value in the input stream
- Returns multiple/arbitary output values for every input
- Returns Stream<R> type
- Syntax:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
- Usage example : Getting the last character of all strings from a list of list of strings
flatMap is a combination of map and flat operation
Consider a 2D object — [[1,2,3],[1,2,3],[1,2,3,]]. If we use a flatmap on this 2D object, then it will return a 1D or one level structure like [1,2,3,1,2,3,1,2,3]
If a map is used in the same structure instead of a flatmap, it returns the 2D structure :
[1,2,3] [1,2,3] [1,2,3]
Explanation with Java8 Code :
import java.util.ArrayList;
import java.util.List;public class tempStreams {
public static void main(String[] args) {
List<List<Integer>> list = new ArrayList<>();
List<Integer> tempList = new ArrayList<>();for(int i=1;i<=3;i++) {
tempList.add(i);
}
for (int j=1;j<=3;j++) {
list.add(tempList);
}
list.stream().map(s -> s).forEach(s->System.out.println(s)); // outputs[1,2,3] [1,2,3] [1,2,3]
list.stream().flatMap(s -> s.stream()).forEach(
s->System.out.println(s));
//outputs 1 2 3 1 2 3 1 2 3
}
}
Add 2 to every element using map in a List of List of Integers:
list = [[1,2,3],
[1,2,3],
[1,2,3]]List<List<Integer>> lists = list.stream().map(s -> s.stream().map(x -> x+2).collect(Collectors.toList())).collect(Collectors.toList());
for(List s : lists) {
System.out.println(s);
}
//prints [3,4,5] [3,4,5] [3,4,5]
As list is a list of integers. We are using a map operation over the outer list. After that we convert the inner list to a stream and go through each individual element to add 2 and return the list. At the end we again convert the outer stream to a list. So we have list of list of Integers as the output.
Same example using flatmap :
List<Integer> lists = list.stream().flatMap(s -> s.stream().map(x -> x+2)).collect(Collectors.toList());
for(Integer s : lists) {
System.out.print(s);
}
//outputs 3 4 5 3 4 5 3 4 5
With flatmap the output type returned is List of Integers not List of List of Integers. Because the purpose of a flatmap is to flatten the list and return the 1D object type structure.
Conclusion
So we use flatmap when we have to change the structure of a stream object and make it flatter; and we use map to do operations on objects so that for every input there’s just one output.
Happy learning. Cheers !