Search code examples
reactive-programmingspring-webfluxproject-reactorreactive

Mono.defualtEmpty() vs Mono.switchIfEmpty()


when upper stream emit nullValue, we can use 'Mono.defualtIfEmpty()' or 'Mono.switchIfEmpty()' to replace null value.

But switchIfEmpty() evaluate upper stream value eager. So we use Mono.defer() for lazy evaluation.

  1. Is 'Mono.defualtIfEmpty()' eager evaluation too? like switchIfEmpty()?

  2. How to change Mono.defualtIfEmpty() to do lazy evaluation?


Solution

  • With defaultIfEmpty, you must provide the fallback value on assembly, so it is necessarily eager.

    As switchIfEmpty takes a Mono as argument, it makes it possible to use it both for eager and lazy evaluation. Apart from cached Mono or Mono.just, most Mono objects/implementations are lazily evaluated.

    In any case, the upstream Mono is not evaluated eagerly, whatever operator you choose.

    The upstream mono is only evaluated upon subscription.

    Example 1 : verify that upstream is not evaluated until subscription :

    var upstream = Mono.fromCallable(() -> {
        System.out.println("UPSTREAM EVALUATION");
        return "upstream";
    });
    
    var defaultIfEmpty = upstream.defaultIfEmpty("default");
    
    System.out.println("Nothing evaluated yet");
    Thread.sleep(2000);
    System.out.println("Still not evaluated");
    
    defaultIfEmpty.block();
    

    Output:

    Nothing evaluated yet
    Still not evaluated
    UPSTREAM EVALUATION
    

    Example 2 : Check that switchIfEmpty is triggered only after upstream evaluation

    var upstream = Mono.fromRunnable(() -> System.out.println("UPSTREAM EVALUATION"));
    var switchEmpty = upstream.switchIfEmpty(Mono.fromCallable(() -> {
            System.out.println("SWITCH EVALUATED");
            return "switch";
    }));
    
    System.out.println("Nothing evaluated yet");
    Thread.sleep(2000);
    System.out.println("Still not evaluated");
    
    switchEmpty.block();
    

    Output:

    Nothing evaluated yet
    Still not evaluated
    UPSTREAM EVALUATION
    SWITCH EVALUATED
    

    Example 3 : SwitchIfEmpty is not evaluated if upstream sends a value :

    var upstream = Mono.fromCallable(() -> {
        System.out.println("UPSTREAM EVALUATION");
        return "upstream";
    });
    
    var switchEmpty = upstream.switchIfEmpty(Mono.fromCallable(() -> {
        System.out.println("SWITCH EVALUATED");
        return "switch";
    }));
    
    System.out.println("Nothing evaluated yet");
    Thread.sleep(2000);
    System.out.println("Still not evaluated");
    
    switchEmpty.block();
    

    Output:

    Nothing evaluated yet
    Still not evaluated
    UPSTREAM EVALUATION