Flux 和 Mono 中的 compose() vs. transform() vs. as() vs. map()

Posted

技术标签:

【中文标题】Flux 和 Mono 中的 compose() vs. transform() vs. as() vs. map()【英文标题】:compose() vs. transform() vs. as() vs. map() in Flux and Mono 【发布时间】:2018-05-01 02:46:48 【问题描述】:

最近,我决定使用 projectreactor.io (io.projectreactor:3.1.1) 尝试 spring 5。

有谁知道使用此功能的最佳情况是什么?使用它们各自的优缺点以及应该在哪里使用它们?

好的例子会有所帮助。

【问题讨论】:

【参考方案1】:

这里有两种截然不同的运算符:

Flux 本身上工作的运算符

transformtransformDeferred 用于代码互化

当您定期编写运算符链并且您的应用程序中有常见的运算符使用模式时,您可以使用transformtransformDeferred 来共享此代码或给它一个更具描述性的名称。

两者之间的区别在于何时应用了相互化的运算符:transform 在实例化时应用它们,而transformDeferred 在订阅时应用它们(允许动态选择添加的运算符)。

查看reference documentation 了解更多详情和示例。

注意:transformDeferred 在 3.3.0 之前的版本中被称为 compose

as

这是一个方便的快捷方式,可以将Function 应用于整个Flux,同时使整个代码保持流畅的风格。一个示例是转换为 Mono(如 javadoc 中所示),但它也可以帮助以工厂方法样式实现的外部运算符。

reactor-addonsMathFlux为例,对比一下:

MathFlux.sumInt(Flux.range(1, 10)
                    .map(i -> i + 2)
                    .map(i -> i * 10))
        .map(isum -> "sum=" + isum);

收件人:

Flux.range(1, 10)
    .map(i -> i + 2)
    .map(i -> i * 10)
    .as(MathFlux::sumInt)
    .map(isum -> "sum=" + isum)

(这可以帮助您处理这样一个事实,即与 Kotlin 不同,Java 没有扩展方法 :))

处理通过Flux 的数据的运算符

map 是关于数据的。当源中的每个元素可用时,它会对源中的每个元素应用 1-1 转换函数。

在上面的 MathFlux 示例中,map 被连续用于将每个原始整数加 2,然后再次将序列中的每个数字乘以 10,最后第三次产生String out of每个总和。

【讨论】:

你能更新你的答案吗?看来compose()已经不存在了……【参考方案2】:

我发现reference documentation 中的示例有点难以理解

所以制作了以下程序来让我了解 transform vs compose 的概念。

fnstatefull = flux -> 
                            Flux<String> f = flux.filter(color -> 
                                //only reds are allowed
                                return color.equalsIgnoreCase("red");   

                            );
                            //applies mapping 'toUpperCase' based on the external control 'toUpper'
                            if(toUpper) 
                                f= f.map(String::toUpperCase);
                            
                            return f;
                        ;

变换

在通量实例化时应用运算符。

fnstatefull 对以下两个订阅者的行为方式相同。

    Flux<String> f = Flux.just("red", "green", "blue");
    toUpper = false;
    f = f.transform(fnstatefull);
    toUpper = true;

    f.subscribe(op -> log.error("ONE>>>" + op));
    toUpper = false;
    f.subscribe(op -> log.error("TWO>>>" + op));

输出

ReactordemoApplication - ONE>>>red
ReactordemoApplication - TWO>>>red

撰写

运算符在订阅时应用于通量。

fnstatefull 对于下面的每个订阅者的行为都会有所不同。

    Flux<String> f = Flux.just("red", "green", "blue");
    toUpper = false;
    f = f.compose(fnstatefull);
    toUpper = true;

    f.subscribe(op -> log.error("ONE>>>" + op));
    toUpper = false;
    f.subscribe(op -> log.error("TWO>>>" + op));

输出

ReactordemoApplication - ONE>>>RED
ReactordemoApplication - TWO>>>red

【讨论】:

以上是关于Flux 和 Mono 中的 compose() vs. transform() vs. as() vs. map()的主要内容,如果未能解决你的问题,请参考以下文章

Flux 和 Mono 的区别

返回 Mono 和 Flux 错误总是返回 500

合并两个 Mono 并获得一个 Flux。然后从那个 Flux 中提取一个 Mono

我对响应式编程中Mono和Flux的理解

如何结合 Mono 和 Flux 作为参数来创建新的 Mono?

从 Mono 的列表中创建 Flux 的正确方法