【问题标题】:Should I use "then" or "flatMap" for control flow?我应该使用“then”还是“flatMap”进行控制流?
【发布时间】:2018-09-17 12:33:31
【问题描述】:

所以,我正在尝试使用 Webflux,并且我有一个场景“检查对象是否存在;如果存在,则执行操作,否则 - 指示错误”。

在reactor中可以写成:

public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){
    return id.
        flatMap(repository::exists). //repository.exists returns Mono<Boolean>
        flatMap(e -> e ? e : Mono.error(new DoesntExistException())). 
        then(
            //can be replaced with just(someBusinessLogic())
            Mono.fromCallable(this::someBusinessLogic) 
        );
}

或作为:

public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){
    return id.
        flatMap(repository::exists). //repository.exists returns Mono<Boolean>
        flatMap(e -> e ? e : Mono.error(new DoesntExistException())). 
        map(e -> this.someBusinessLogic()));
}

假设someBusinessLogic的返回类型不能改变,它必须是简单的void,而不是Mono&lt;Void&gt;

在这两种情况下,如果对象不存在,则会生成适当的Mono.error(...)

虽然我知道thenflatMap 具有不同的语义,但实际上我得到了相同的结果。即使在第二种情况下,我使用 flatMap 与它的含义相反,我也可以跳过 flatMapfromCallable 以支持简单的 map 并忽略参数(这似乎更具可读性)。我的观点是,在可读性和代码质量方面,这两种方法各有利弊。

所以,总结一下:

然后使用

  • 优点
    • 语义正确
  • 缺点
    • 在许多情况下(如上)需要包装在 ad-hoc Mono/Flux 中

使用平面地图

  • 优点
    • 简化了持续的“快乐场景”代码
  • 缺点
    • 语义不正确

这两种方法的其他优点/缺点是什么?选择运营商需要注意什么?

我发现this reactor issue 表明速度没有真正的差异。

【问题讨论】:

    标签: java reactive-programming reactor


    【解决方案1】:

    TL, DR:如果你关心之前计算的结果,你可以使用map()flatMap()或其他map变体。否则,如果您只想完成上一个流,请使用then()

    您可以通过在这两种方法中调用.log() 来查看自己的详细执行日志:

    public Mono<Void> handleObjectWithSomeId(Mono<IdType> id) {
        return id.log()
                 .flatMap(...)
                 ...;
    }
    

    与 Project Reactor 中的所有其他操作一样,then()flatMap() 的语义已经定义。上下文主要定义了这些运算符应如何协同工作来解决您的问题。

    让我们考虑一下您在问题中提供的上下文。 flatMap() 所做的是,每当它收到一个事件时,它就会异步执行映射函数。

    由于我们在问题中的最后一个flatMap() 之后有一个Mono&lt;&gt;,它将提供先前单个计算的结果,我们忽略它。请注意,如果我们改为使用 Flux&lt;&gt;,则将对每个元素进行计算。

    另一方面,then() 并不关心前面的事件序列。它只关心 completion 事件:

    这就是为什么,在您的示例中,您使用哪一个并不重要。但是,在其他情况下,您可能会做出相应的选择。

    您可能还会发现 Which operator do I need? 部分 Project Reactor Reference 很有帮助。

    【讨论】:

    • 您的解释措辞很好,我想有些人会觉得它有帮助,但不幸的是它没有回答我的问题。我确实了解这两个运算符的工作原理,我只是想知道这种基于 Mono 的错误的特定情况。我现在只是想知道在 then() 和 flatMap() 的情况下何时调用 onComplete 是否有区别,例如 then() 是否完成了上一个流,而 flatMap 将等待下一个流首先完成。
    • 下一个或上一个流到底是什么意思?如果onComplete 是您所追求的,图表描述了终止事件。
    • 如果您对错误流感兴趣,两个操作都会在出现异常时发出错误事件,或者由操作发出Mono.error(...)onErrorXxxx() 处理程序将捕获任何错误。无论如何,我建议您在方法中添加log() 语句,以实际查看发生了什么。
    猜你喜欢
    • 2020-11-02
    • 2020-11-19
    • 1970-01-01
    • 2018-01-26
    • 2018-02-03
    • 2013-06-06
    • 2020-06-06
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多