javareactor

Returning a null in a .map() versus .flatMap() in Reactor


The following piece of code works :

// emitting employees...
.flatMap(employee -> {

    boolean isAlive = employee.isAlive();

    return Mono.just(isAlive)

            .flatMap(myBoolean -> {
                if (myBoolean) {
                    return Mono.empty();
                } 
                else {
                    return Mono.just(employee);
                }
            });

})

But I was wondering why I can't use a .map upon processing myBoolean (NullPointerException when it returns the null)

            .map(myBoolean -> {
                if (myBoolean) {
                    return null;
                } 
                else {
                    return employee;
                }
            });

I believe I lack some understanding about the map versus flatMap

In Java 8 streams I understand the difference between map and flatMap (for each item received, map emits 1, flatMap emits N)

But in Reactor I'm a bit confused. I thought that both map and flatMap emit 1 item for each element received, the difference would be that the map emits it as a Mono while flatMap doesn't. To emit N items, I would use flatMapMany.

Thanks in advance for your explanations !


Solution

  • From Reactor java doc

    map: Transform the item emitted by this Mono by applying a synchronous function to it.

    flatMap: Transform the item emitted by this Mono asynchronously, returning the value emitted by another Mono.

    In all cases, you cannot return null. It is simply forbidden by design. The main difference between map and flatMap is that the second one returns a Mono. This allows to perform an asynchronous call to something like a data base, a web service, etc.

    So flatMap should be used to performed another asynchronous stuff. It's not very useful if you return a Mono.just(...). We may use flatMap to return Mono.empty() in some condition as you did. It is a frequent pattern. Depending on your use case, you may prefer to use filter or mapNotNull.

    Here an alternative code to emit a new object with a condition:

            .handle(myBoolean, sink -> {
                if (!myBoolean) {
                    sink.next(employee);
                } // else the Mono would be empty ...
            });