我应该使用“then”或“flatMap”来控制流量吗?

时间:2018-04-07 18:10:49

标签: java reactive-programming reactor

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

这可以写在反应堆中:

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<Void>

在这两种情况下,如果对象不存在,将生成相应的Mono.error(...)

虽然我理解thenflatMap具有不同的语义,但实际上我得到了相同的结果。即使在第二种情况下我使用flatMap来反对它的含义,我也会跳过flatMapfromCallable,而不是简单的map使用忽略的参数(这看起来更具可读性) )。我的观点是,在可读性和代码质量方面,两个apporaches都有优点和缺点。

所以,这是一个总结:

使用

  • 正反
    • 在语义上是正确的
  • 缺点
    • 在许多情况下(如上所述)需要在ad-hoc Mono / Flux中进行包装

使用flatMap

  • 正反
    • 简化了持续的“快乐方案”代码
  • 缺点
    • 在语义上不正确

这两种方法的其他优点/缺点是什么?选择运营商时应该考虑什么?

我发现this reactor issue表示速度没有实际差异。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

让我们考虑一下您在问题中提供的背景。 flatMap()的作用是,只要它获得一个事件,就会异步执行映射函数。

Write(Byte\[\], int, int)

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

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

flatmap marble diagram

这就是为什么,在你的例子中,你使用哪一个并不重要。但是,在其他情况下,您可以相应地选择。

您可能还会发现enter image description here部分项目反应器参考有用。