본문 바로가기
spring/spring webFlux

[webFlux] SwitchIfEmpty가 항상 호출되는 이슈 해결 (Lazy Evaluation)

by moonsiri 2022. 12. 20.
728x90
반응형

webflux에서 if else문으로 switchIfEmpty를 주로 사용하는데, empty가 아닌 경우에도 switchIfEmpty를 항상 호출합니다. 왜 그러는 것인지, 어떻게 하면 호출을 안 하게 할 수 있는지 알아보겠습니다.

switchIfEmpty

 

1: String str = "str";
2: Mono.just(str)
3:     .map(s -> {
4:         System.out.println(s);
5:         return s;
6:     })
7:     .switchIfEmpty({
8:         System.out.println("defaultStr");
9:         return Mono.just("default");
10:    })
11:    .subscribe();


위 코드를 보면 str이 비어 있지 않으니 문자열 "str"만 출력할 것이라고 생각하겠지만, 실제로는 "defaultStr", "str" 둘 다 출력이 됩니다.

<console>
defaultStr
str


자바는 보통 메서드 매개변수의 값을 미리 결정시켜놓으려고 합니다(eager evaluation). 그래서 실제 map을 실행하기 전에 switchIfEmpty를 먼저 실행시켜 값을 만들어 놓기때문에 실제 실행 순서는 (1 - 2 - 3 - 4 - 5)가 아닌 (1 - 2 - 7 - 8 - 3 - 4 - 5)가 됩니다.
만약 switchIfEmpty 안에 실행되는 메서드가 비용이 크고, 실제로 Mono.just가 empty를 반환하지 않는다면, 굳이 실행되지 않아도 되는 비싼 비용의 메서드를 호출해야 합니다. 이럴 때 우리는 불필요한 연산을 피하는 lazy evaluation 전략을 사용하여 switchIfEmpty 안의 실행을 실제 필요 시점으로 미룰 수 있게 할 수 있습니다.

String str = "str";
Mono.just(str)
    .map(s -> {
        System.out.println(s);
        return s;
    })
    .switchIfEmpty(Mono.defer(() -> {
        System.out.println("defaultStr");
        return Mono.just("default");
    }))
    .subscribe();
String str = "str";
Mono.just(str)
    .map(s -> {
        System.out.println(s);
        return s;
    })
    .switchIfEmpty(Mono.fromSupplier(() -> {
        System.out.println("defaultStr");
        return "default";
    }))
    .subscribe();


위와 같이 Mono.defer 혹은 Mono.fromSupplier를 사용하면 해당 메서드의 매개변수로 Supplier를 넘기기 때문에 미리 값을 만들어 놓지 않고, 실제 호출되는 시점으로 실행을 지연시킬 수 있습니다.

  • just : 즉시 시퀀스를 생성.
  • fromSupplier : 구독시점에 시퀀스를 생성. return type이 Supplier<? extends T>.
  • defer : 구독 시점에 시퀀스를 생성. return type이 Supplier<? extends Mono<? extends T>> 이므로 Mono로 반환되는 메서드에 사용하는 것이 좋음.

 



[Reference]
https://projectreactor.io/docs/core/3.2.16.RELEASE/kdoc-api/reactor.core.publisher/switch-if-empty.html
https://coding-start.tistory.com/372
https://stackoverflow.com/questions/54373920/mono-switchifempty-is-always-called

728x90
반응형

댓글