在 .map() 中返回 null 与在 Reactor 中返回 .flatMap()

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

以下代码有效:

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

    boolean isAlive = employee.isAlive();

    return Mono.just(isAlive)

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

})

但我想知道为什么我不能在处理 myBoolean 时使用 .map(当它 returns 为 null 时出现 NullPointerException)

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

我想我对 mapflatMap

缺乏一些了解

在 Java 8 个流中,我了解 mapflatMap 之间的区别(对于收到的每个项目,map 发出 1,flatMap 发出 N )

但是在 Reactor 中我有点困惑。我认为 mapflatMap 都会为收到的每个元素发出 1 个项目,不同之处在于 map 将其作为 Mono 发出,而 flatMap 不会't。要发出 N 项,我会使用 flatMapMany.

提前感谢您的解释!

使用map方法映射Mono的内容时,不能提供null作为映射结果,因为那样会导致 java.lang.NullPointerException: The mapper returned a null value. 订阅期间。

Mono 可以为空或必须包含有效对象。

根据Project Reactor的源码,Mono的内容不能为null。

所以在这种情况下,有效的解决方案是使用 flatMap

那是因为 flatMap 将尝试在外部单声道中展开内部单声道。这意味着该值将为 null 但会有一个类型..

另一方面,map 会将 Mono<A> 转换为 Mono<B>。 null 没有类型,这就是你不能这样做的原因。

来自反应堆java doc

map:通过对其应用同步函数来转换此 Mono 发出的项目。

flatMap:异步转换此 Mono 发出的项目,returning 另一个 Mono 发出的值。

在所有情况下,您都不能 return null。它只是被设计禁止的。 mapflatMap 之间的主要区别是第二个 return 是单声道。这允许对数据库、Web 服务等执行异步调用。

所以flatMap应该用来执行另一个异步操作。如果你 return 一个 Mono.just(...) 就不是很有用了。我们可能会像您一样在某些情况下使用 flatMap 来 return Mono.empty() 。这是一个常见的模式。

这里是一个替代代码,用于发出具有条件的新对象:

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

A null 在你的信息流中的任何地方都会抛出一个 NPE: Mapper returned a null value。不管map还是flatMap。这是设计使然。

关于 flatMap 的简短说明:它急切地订阅其内部流(在您的情况下,Mono.empty()Mono.just(..))并在内部流不断发出时进行动态合并元素。这就是为什么您可以使用 flatMap.

保证订单的原因

为避免出现 NullPointerException,您可以将 map 更改为 mapNotNull:

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

您可以在map之前添加过滤器:

.filter(Objects::nonNull)
.filter(myBoolean -> myBoolean)
.map(r-> employee)
.switchIfEmpty(Mono.empty());