map vs flatMap in stream
현재 진행중인 사이드 프로젝트에서 사용하는 WebFlux를 분석하면서 정리한 글입니다.
자바에서 Stream 인터페이스 메서드인 map()과 flatMap()는 중개 오퍼레이션 역할을 수행합니다.
중개 오퍼레이션이므로 메소드 출력으로 다른 스트림을 반환합니다.
map()과 flatMap()은 모두 변환 및 매핑 작업에 사용됩니다.
map()은 하나의 입력 값에 대해 하나의 출력을 생성하는 반면, flatMap()은 각 입력 값에 대해 출력으로 임의의 수의 값을 생성합니다(0 이상).
- R : 새 스트림의 요소 타입
- 스트림 : 인터페이스
- T : 스트림 요소의 타입
- mapper : 각 요소에 적용되는 상태 비저장 함수
map(), flatMap() 둘 다 새 스트림을 반환합니다.
map
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
map()은 특정 컬렉션의 요소를 특정 함수에 매핑한 다음 업데이트된 결과를 포함하는 스트림을 반환해야 하는 곳에서 사용할 수 있습니다.
map 같은 경우는 A라는 Container 타입으로 둘러 쌓인 원소를 꺼내서 처리를 해준 뒤, 다시 A Container 타입으로 감싸는 역할을 수행합니다.
ex) 목록의 모든 요소에 3을 곱하고 업데이트된 목록을 반환합니다.
flatMap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
map()으로는 문자열을 flatten 혹은 transform 할 수 없기 때문에 이와 같은 작업이 필요할 때에는 flatMap()을 사용합니다.
ex) 문자열 목록에 있는 모든 문자열의 첫 번째 문자를 가져오고 스트림 형식으로 결과를 반환합니다.
다음 코드를 예로 들어보겠습니다.
@GetMapping
public Mono<String> rest(int idx) {
Mono<ClientResponse> res = client.get().uri(URL1, idx).exchange();
Mono<Mono<String>> body = res.map(clientResponse -> clientResponse.bodyToMono(String.class));
위 body처럼 map으로 처리하게 되면 Mono에 감싸진 Mono<String>를 얻게 됩니다.
그렇기 때문에 flatMap을 사용해야 합니다.
flatMap은 A라는 Container 타입으로 감싸는 역할을 수행하지 않기 때문입니다.
map example code
import java.io.*;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
class Main {
public static void main(String[] args)
{
// making the array list object
ArrayList<String> fruit = new ArrayList<>();
fruit.add("Apple");
fruit.add("mango");
fruit.add("pineapple");
fruit.add("kiwi");
System.out.println("List of fruit-" + fruit);
// lets use map() to convert list of fruit
List list = fruit.stream()
.map(s -> s.length())
.collect(Collectors.toList());
System.out.println("List generated by map-" + list);
}
}
// 실행 결과
List of fruit-[Apple, mango, pineapple, kiwi]
List generated by map-[5, 5, 9, 4]
flatMap example code
import java.io.*;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
class GFG {
public static void main(String[] args)
{
// making the arraylist object of List of Integer
List<List<Integer> > number = new ArrayList<>();
// adding the elements to number arraylist
number.add(Arrays.asList(1, 2));
number.add(Arrays.asList(3, 4));
number.add(Arrays.asList(5, 6));
number.add(Arrays.asList(7, 8));
System.out.println("List of list-" + number);
// using flatmap() to flatten this list
List<Integer> flatList
= number.stream()
.flatMap(list -> list.stream())
.collect(Collectors.toList());
// printing the list
System.out.println("List generate by flatMap-"
+ flatList);
}
}
// 실행 결과
List of list-[[1, 2], [3, 4], [5, 6], [7, 8]]
List generate by flatMap-[1, 2, 3, 4, 5, 6, 7, 8]
reference
Difference Between map() And flatMap() In Java Stream - GeeksforGeeks
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html