我应该使用“那么"吗?或“平面地图"用于控制流? [英] Should I use "then" or "flatMap" for control flow?

查看:33
本文介绍了我应该使用“那么"吗?或“平面地图"用于控制流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这可以写在反应堆中:

public MonohandleObjectWithSomeId(Mono id){返回标识.flatMap(repository::exists).//repository.exists 返回 MonoflatMap(e -> e ? e : Mono.error(new DontExistException())).然后(//可以用just(someBusinessLogic())替换Mono.fromCallable(this::someBusinessLogic));}

或作为:

public MonohandleObjectWithSomeId(Mono id){返回标识.flatMap(repository::exists).//repository.exists 返回 MonoflatMap(e -> e ? e : Mono.error(new DontExistException())).map(e -> this.someBusinessLogic()));}

假设 someBusinessLogic 的返回类型不能改变,它必须是简单的 void,而不是 Mono.>

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

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

所以,这是一个总结:

使用然后

  • 优点
    • 在语义上是正确的
  • 缺点
    • 在许多情况下(如上所示)需要在临时 Mono/Flux 中进行包装

使用 flatMap

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

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

我发现

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

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

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

您可能还会找到我需要哪个运算符? 部分 Project Reactor 参考很有帮助.

So, I'm trying to work with Webflux and I've got a scenario "check if an object exists; if so, do stuff, else - indicate error".

That can be written in reactor as:

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) 
        );
}

or as:

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()));
}

Let's assume that return type of someBusinessLogic cannot be changed and it has to be simple void, not Mono<Void>.

In both cases if the object won't exist, appropriate Mono.error(...) will be produced.

While I understand that then and flatMap have different semantics, effectively I get the same result. Even though in second case I'm using flatMap against its meaning, I get to skip flatMap and fromCallable in favor of simple map with ignored argument (that seems more readable). My point is, both apporaches have advantages and disadvantages when it comes to readability and code quality.

So, here's a summary:

Using then

  • pros
    • is semantically correct
  • cons
    • in many cases (like above) requires wrapping in ad-hoc Mono/Flux

Using flatMap

  • pros
    • simplifies continued "happy scenario" code
  • cons
    • is semantically incorrect

What are other pros/cons of both approaches? What should I take under consideration when choosing an operator?

I've found this reactor issue that states that there is not real difference in speed.

解决方案

TL, DR: If you care about the result of the previous computation, you can use map(), flatMap() or other map variant. Otherwise, if you just want the previous stream finished, use then().

You can see a detailed log of execution for yourself, by placing an .log() call in both methods:

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


Like all other operations in Project Reactor, the semantics for then() and flatMap() are already defined. The context mostly defines how these operators should work together to solve your problem.

Let's consider the context you provided in the question. What flatMap() does is, whenever it gets an event, it executes the mapping function asynchronously.

Since we have a Mono<> after the last flatMap() in the question, it will provide the result of previous single computation, which we ignore. Note that if we had a Flux<> instead, the computation would be done for every element.

On the other hand, then() doesn't care about the preceding sequence of events. It just cares about the completion event:

That's why, in your example it doesn't matter very much which one you use. However, in other contexts you might choose accordingly.

You might also find the Which operator do I need? section Project Reactor Reference helpful.

这篇关于我应该使用“那么"吗?或“平面地图"用于控制流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆