ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Reactor List가 비어있을 때의 switchIfEmpty와 defaultIfEmpty
    Spring/Spring 2021. 10. 14. 11:47

    Reactor 에서 Mono나 Flux가 비어 있는 경우 대체 값을 제공하는 switchIfEmpty와 defaultIfEmpty 연산자는 매우 유용하다. 이 글에서는 이 두 연산자의 차이점과 사용 예제, 그리고 이를 통해 얻을 수 있는 장점을 살펴보자.

    switchIfEmpty와 defaultIfEmpty의 차이점


    switchIfEmpty

    switchIfEmpty는 원래 Mono나 Flux가 비어 있을 때 (즉, Mono.empty()나 Flux.empty()인 경우) 대체 Mono나 Flux를 제공하는 연산자이다. 이는 데이터 스트림이 비어 있는 상황에서 다른 데이터 소스로 대체할 때 유용하다.

    fun getKeywords(info: String, key: String): Mono<List<String>> {
        return if (key.isEmpty()) {
            Mono.empty() // 비어 있는 Mono 반환
        } else {
            Mono.just(listOf(key))
        }
    }
    
    val keywords = getKeywords("info", "")
        .switchIfEmpty(getKeywords("info", "convertedKey"))
        .onErrorResume { Mono.just(listOf()) }
    
    keywords.subscribe { result ->
        println("Keywords: $result")
    }

    위 코드에서 getKeywords가 Mono.empty()를 반환하면 switchIfEmpty가 실행되어 convertedKey를 사용하는 대체 Mono가 호출된다.

     

     

     

     

     

    위 마블 다이어그램에서, 원래의 Mono가 비어 있을 경우 대체 Mono로 전환되는 과정을 보여준다.

    defaultIfEmpty

    defaultIfEmpty는 원래 Mono나 Flux가 실제 값으로 비어 있는 경우, 예를 들어 Mono.just(emptyList())와 같이 빈 리스트를 포함하는 경우에 대체 값을 제공하는 연산자이다. 이는 데이터가 비어 있을 때 기본값을 설정할 때 유용하다.

    fun getKeywords(info: String, key: String): Mono<List<String>> {
        return if (key.isEmpty()) {
            Mono.just(emptyList()) // 빈 리스트를 포함하는 Mono 반환
        } else {
            Mono.just(listOf(key))
        }
    }
    
    val keywords = getKeywords("info", "")
        .defaultIfEmpty(listOf("defaultValue"))
        .onErrorResume { Mono.just(listOf()) }
    
    keywords.subscribe { result ->
        println("Keywords: $result")
    }

    위 코드에서 getKeywords가 Mono.just(emptyList())를 반환하면 defaultIfEmpty가 실행되어 Mono.just(listOf("defaultValue"))를 반환한다.

     

     

    Reactor의 비어 있는 리스트 처리


    Reactor에서는 Mono와 Flux를 사용하여 비동기적인 데이터 스트림을 처리할 수 있다. 이때 데이터가 비어 있을 수 있는 상황을 처리하는 것은 중요하다. switchIfEmpty와 defaultIfEmpty를 적절히 사용하면 이러한 상황에서 보다 유연하고 안정적인 코드를 작성할 수 있다.

    switchIfEmpty와 defaultIfEmpty의 혼용 사용 방지


    이 두 연산자는 비슷해 보이지만, 각각의 목적이 다르다. switchIfEmpty는 원래 스트림이 완전히 비어 있을 때 (즉, Mono.empty()나 Flux.empty()일 때) 사용되고, defaultIfEmpty는 스트림이 실제 값으로 비어 있을 때 (예: Mono.just(emptyList())) 사용된다. 따라서, 리스트가 비어 있는 경우 switchIfEmpty를 사용하는 것은 적절하지 않다.

    val keywords = getKeywords("info", "")
        .switchIfEmpty(Mono.just(listOf("defaultValue"))) // 잘못된 사용

     

    이 경우 getKeywords가 Mono.just(emptyList())를 반환해도 switchIfEmpty가 실행되지 않기 때문에, 예상한 대로 동작하지 않는다.

     

    실용적인 사용 사례

    1. API 호출 시 대체 데이터 소스 제공:
      • 메인 API 호출이 실패하거나 결과가 비어 있을 때 백업 API를 호출하여 대체 데이터를 제공할 수 있다.
    2. 기본값 설정:
      • 데이터베이스 조회 결과가 비어 있을 때 기본값을 설정하여 애플리케이션이 예상치 못한 NullPointerException을 방지할 수 있다.
    3. 캐시 메커니즘:
      • 캐시된 데이터가 없을 때, 원본 데이터 소스를 호출하고 그 결과를 캐시에 저장하는 방식으로 사용할 수 있다.

     

    switchIfEmpty는 원래 스트림이 완전히 비어 있을 때 대체 스트림을 제공하며, defaultIfEmpty는 스트림이 실제 값으로 비어 있을 때 기본값을 설정한다. 이 두 연산자를 적절히 사용하면 비동기 데이터 처리에서 더욱 안정적이고 유연한 코드를 작성할 수 있다. 상황에 맞게 이 연산자들을 활용하여 효율적인 비동기 프로그램을 작성해보자.

Designed by Tistory.