【问题标题】:Returning a null in a .map() versus .flatMap() in Reactor在 .map() 与 Reactor 中的 .flatMap() 中返回 null
【发布时间】:2019-10-03 09:08:11
【问题描述】:

以下代码有效:

// 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(返回 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 不会。要发出 N 个项目,我会使用 flatMapMany

提前感谢您的解释!

【问题讨论】:

  • 我最近在 flatMap 上写的一篇博文:medium.com/swlh/…。您可能会发现它很有用。

标签: java reactor


【解决方案1】:

来自反应堆java doc

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

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

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

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

这里有一个替代代码来发出一个带有条件的新对象:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      Mono 可以为空,也可以包含有效对象。

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

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

      【讨论】:

        【解决方案4】:

        流中任何位置的null 都会抛出NPE: Mapper returned a null value。无论map 还是flatMap。这是设计使然。

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

        【讨论】:

          【解决方案5】:

          为避免在您的情况下出现 NullPointerException,您可以将 map 更改为 mapNotNull:

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-06-30
              • 2018-07-07
              • 1970-01-01
              • 2010-11-06
              • 1970-01-01
              • 2021-04-11
              • 1970-01-01
              • 2016-07-18
              相关资源
              最近更新 更多