공부 기록/Spring

[Spring WebFlux] CollectMap에 대하여

뵤옹 2023. 4. 10. 11:14

CollectMap이란?

  •  CollectMap은 Map 콜랙션으로 데이터를 모으는 리액터 모으기(aggregation) 연산 중 하나이다.
  • 리액터 모으기의 종류에는 collectMap 이외에도 아래와 같은 종류가 있다.
1. List 형식으로 모으기 : collectList
2. Map의 값을 모으기 : collectMultiMap
3. 개수 새기 : count
4. 누적하기 : reduce
5. 누적하면서 값 생성하기 : scan

CollectMap의 형식

  • Mono<Map<K, T>> collectMap(Function<? super T, ? extends K> keyExtractor)
  • Mono<Map<K, V>> collectMap(Function<? super T, ? extends K> keyExtractor,
                                              Function<? super T, ? extends V> valueExtractor)
  • Mono<Map<K, V>> collectMap(Function<? super T, ? extends K> keyExtractor,
                                              Function<? super T, ? extends V> valueExtractor,
                                              Supplier<Map<K, V>> mapSupplier)

collectMap의 형식에 따른 인자는 다음과 같다.

  • key Extractor : 데이터에서 map의 key를 제공하는 함수
  • value Extractor : 데이터에서 map의 value를 제공하는 함수
  • mapSupplier : 사용할 map 객체를 제공(mapSupplier가 없는 메서드는 기본으로 HashMap을 사용)
// keyExtractor만 지정. 값은 그대로 사용.
Mono<Map<Integer, Tuple2<Integer, String>>> numTupMapMono =
        Flux.just(Tuples.of(1, "일"), Tuples.of(2, "이"), Tuples.of(3, "삼"), Tuples.of(4, "사"))
                .collectMap(x -> x.getT1()); // keyExtractor


// String을 리턴하는 valueExtractor 사용.
Mono<Map<Integer, String>> numLabelMapMono =
        Flux.just(Tuples.of(1, "일"), Tuples.of(2, "이"), Tuples.of(3, "삼"), Tuples.of(4, "사"))
                .collectMap(x -> x.getT1(), // keyExtractor
                        x -> x.getT2()); // valueExtractor


// Map으로 TreeMap 사용
Mono<Map<Integer, String>> numLabelTreeMapMono =
        Flux.just(Tuples.of(1, "일"), Tuples.of(2, "이"), Tuples.of(3, "삼"), Tuples.of(4, "사"))
                .collectMap(x -> x.getT1(), // keyExtractor
                        x -> x.getT2(), // valueExtractor
                        () -> new TreeMap<>()); // mapSupplier

특징

collectMap은 중복된 키가 존재하면 마지막 데이터와 관련된 값이 사용된다.

예를 들어 아래와 같이 Flux가 생성하는 데이터는 4개지만 키로 사용하는 값이 중복되면 실제 map에는 3과 4, 두 개의 데이터만 저장된다.

Flux.just(1, 2, 3, 4)
     .collectMap(x -> x % 2)
     .subscribe(map -> System.out.println(map)); // {0=4, 1=3}

예제

@Test
public void collectMap() {
    Flux<String> animalFlux = Flux.just(
        "aardvark", "elephant", "koala", "eagle", "kangaroo");

    Mono<Map<Character, String>> animalMapMono = 
        animalFlux.collectMap(a -> a.charAt(0));

    StepVerifier
        .create(animalMapMono)
        .expectNextMatches(map -> {
            return
                map.size() == 3 &&
                map.get('a').equals("aardvark") &&
                map.get('e').equals("eagle") &&
                map.get('k').equals("kangaroo");
        })
        .verifyComplete();

Map의 key는 동물의 첫 번째 문자로 결정되고 value는 동물 이름 자체가 된다.( {'a':'aardvark'} )

elephant, eagle과 같이 첫 글자가 같은 경우는 나중에 나온 eagle이 value가 된다.

 


참조

https://javacan.tistory.com/entry/Reactor-Start-8-Aggregation

https://backtony.github.io/spring/2022-06-16-spring-webflux-1/

 

(후에 다른 다른 모으기 연산들이 추가될 수 있습니다.)