RxJava 中的 concatMap 和 flatMap 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24571491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 13:05:46  来源:igfitidea点击:

What is the difference between concatMap and flatMap in RxJava

javarx-javaflatmapconcatmap

提问by Haspemulator

It seems that these 2 functions are pretty similar. They have same signature (accepting rx.functions.Func1<? super T, ? extends Observable<? extends R>> func), and their marble diagrams look exactly same. Can't paste the pics here, but here's one for concatMap, and here's one for flatMap. There seems to be some subtle difference in the description of resulting Observable, where one produced by concatMapcontains items that result from concatinating resulting Observables, and the one produced by flatMapcontains items that result from first merging the resulting Observables, and emitting the result of that merger.

看起来这两个功能非常相似。它们具有相同的签名(接受rx.functions.Func1<? super T, ? extends Observable<? extends R>> func),并且它们的大理石图看起来完全相同。无法在此处粘贴图片,但这里是concatMap 的一张,这是flatMap的一张。对 result的描述似乎有一些细微的差异Observable,其中产生的concatMap包含由连接结果 Observables 产生的flatMap项目,而产生的包含由首先合并结果 Observables 并发出合并结果产生的项目。

However, this subtlety is totally unclear to me. Can anyone give a better explanation of this difference, and ideally give some examples illustrating this difference.

然而,我完全不清楚这种微妙之处。任何人都可以更好地解释这种差异,并且最好给出一些说明这种差异的例子。

采纳答案by Marek Hawrylczak


As you wrote, the two functions are very similar and the subtle difference is how the output is created ( after the mapping function is applied).


正如您所写,这两个函数非常相似,细微的区别在于如何创建输出(应用映射函数之后)。

Flat map uses merge operatorwhile concatMap uses concat operator.

平面地图使用合并运算符,而 concatMap 使用concat 运算符

As you see the concatMap output sequence is ordered - all of the items emitted by the first Observable being emitted before any of the items emitted by the second Observable,
while flatMap output sequence is merged - the items emitted by the merged Observable may appear in any order, regardless of which source Observable they came from.

正如你看到的 concatMap 输出序列是有序的 - 第一个 Observable 发出的所有项目在第二个 Observable 发出的任何项目之前发出,
而 flatMap 输出序列被合并 - 合并的 Observable 发出的项目可能出现在任何顺序,无论它们来自哪个源 Observable。

回答by WindRider

One very important difference: the concatMapwaits for the current emitted observable to complete and flatMapdoesn't. flatMaptries to start as many possible. Simply said - you cannot concatenate something infinite. Just make sure that the observables you emit in concatMapcan complete, otherwise the whole flow will get stuck waiting for the current observable to complete to concatenate the next one.

一个非常重要的区别:concatMap等待当前发出的 observable 完成而flatMap没有。flatMap尝试尽可能多地开始。简单地说 - 你不能连接无限的东西。只要确保您发出的 observableconcatMap可以完成,否则整个流程将卡住等待当前 observable 完成以连接下一个。

回答by Anatolii

Even though the answers here are good it wasn't easy to spot the difference without an example. So, I created a simple example for this:

尽管这里的答案很好,但如果没有示例,也不容易发现差异。因此,我为此创建了一个简单的示例:

@Test
public void flatMapVsConcatMap() throws Exception {
    System.out.println("******** Using flatMap() *********");
    Observable.range(1, 15)
            .flatMap(item -> Observable.just(item).delay(1, TimeUnit.MILLISECONDS))
            .subscribe(x -> System.out.print(x + " "));

    Thread.sleep(100);

    System.out.println("\n******** Using concatMap() *********");
    Observable.range(1, 15)
            .concatMap(item -> Observable.just(item).delay(1, TimeUnit.MILLISECONDS))
            .subscribe(x -> System.out.print(x + " "));

    Thread.sleep(100);
}

******** Using flatMap() *********

1 2 3 4 5 6 7 9 8 11 13 15 10 12 14

******** Using concatMap() *********

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

******** 使用 flatMap() *********

1 2 3 4 5 6 7 9 8 11 13 15 10 12 14

******** 使用 concatMap() *********

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

As it could be seen from the output, the results for flatMapare unordered while for concatMapthey're.

从输出中可以看出, 的结果flatMap是无序的,而concatMap它们是无序的。

回答by Ashish Mishra

First of all, flatMap is same as mergeMap in Rxjs. So that is one confusion less. So there are two observables..

首先,flatMap 与 Rxjs 中的 mergeMap 相同。所以这少了一种混淆。所以有两个 observable..

1) o1: A simple list of items from(['Kitty','Donald','Batman'])

1) o1:来自(['Kitty','Donald','Batman']) 的简单项目列表

2) process_o1(): process_o1() is a function that takes as one parameter 'item' and does something with it and returns an Observable which on completion emits 'done with [item]'.

2) process_o1(): process_o1() 是一个函数,它接受一个参数“item”并用它做一些事情并返回一个 Observable,它在完成时发出“done with [item]”。

o1.pipe(mergeMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});

Here we are going to see:- done with Kity.

在这里,我们将看到:- 用 Kity 完成。

done with Donald.

完成与唐纳德。

done with Batman.

完成与蝙蝠侠。

without any guarantee that Kitty comes before Donald and Donald comes before Batman. This is because, as soon as the outer observable emits an item the inner observable is subscribed.

不能保证凯蒂先于唐纳德,唐纳德先于蝙蝠侠。这是因为,一旦外部 observable 发出一个项目,内部 observable 就会被订阅。

=== But in case of concatMap:-

=== 但是在 concatMap 的情况下:-

o1.pipe(concatMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});

We have the guarantee of the below sequence:-

我们有以下顺序的保证:-

done with Kity.

与凯蒂完成。

done with Donald.

完成与唐纳德。

done with Batman.

完成与蝙蝠侠。

Because, with concatMap operator, the inner Observable is not subscribed before the previous inner Observable returns.

因为,使用 concatMap 运算符,在前一个内部 Observable 返回之前,内部 Observable 不会被订阅。

The outer observable is free to just go ahead and emit all its values, but the concatMap will make sure that it deals with each of those values one by one and maintains the order. Hence the name concatMap.

外部 observable 可以自由地继续并发出它的所有值,但是 concatMap 将确保它一个一个地处理这些值中的每一个并保持顺序。因此名称为 concatMap。

In crux, if you are keen on maintaining the order of doing things, you should use concatMap. But if you dont care about order, you can go ahead with mergeMap which will subscribe to all inner Observables at once and keep emitting values as and when they return.

关键是,如果你热衷于维护做事的顺序,你应该使用concatMap。但是如果你不关心顺序,你可以继续使用 mergeMap 它会立即订阅所有内部 Observables 并在它们返回时继续发出值。

回答by Efimov Alex

I find example in most upvoted answer not much clear, so i post one that helped me to understand difference between flatMap and concatMap.

我发现大多数赞成的答案中的例子不太清楚,所以我发布了一个帮助我理解 flatMap 和 concatMap 之间区别的例子。

FlatMap takes emissions from source observable, then create new observable and mergeit to original chain, while concatMap concatit to original chain.

FlatMap需要排放源可观察到的,然后创建新观察到的,并合并其原来的链条,而concatMap Concat的它原来的链条。

Main difference is that concatMap() will merge each mapped Observable sequentially and fire it one at a time. It will only move to the next Observable when the current one calls onComplete().

主要区别在于 concatMap() 将按顺序合并每个映射的 Observable 并一次触发一个。只有当当前 Observable 调用 onComplete() 时,它才会移动到下一个 Observable。

Here is flatMapexample:

这是flatMap示例:

private void flatMapVsConcatMap() throws InterruptedException {
    Observable.just(5, 2, 4, 1)
            .flatMap(
                    second ->
                            Observable.just("Emit delayed with " + second + " second")
                                    .delay(second, TimeUnit.SECONDS)
            )
            .subscribe(
                    System.out::println,
                    Throwable::printStackTrace
            );

    Thread.sleep(15_000);
}

Will result in :

将导致:

Emit delayed with 1 second
Emit delayed with 2 second
Emit delayed with 4 second
Emit delayed with 5 second

Emit 延迟 1 秒
Emit 延迟 2 秒
Emit 延迟 4 秒
Emit 延迟 5 秒

Here is concatMapexample:

这是concatMap示例:

private void flatMapVsConcatMap() throws InterruptedException {
    Observable.just(5, 2, 4, 1)
            .concatMap(
                    second ->
                            Observable.just("Emit delayed with " + second + " second")
                                    .delay(second, TimeUnit.SECONDS)
            )
            .subscribe(
                    System.out::println,
                    Throwable::printStackTrace
            );

    Thread.sleep(15_000);
}

Will result in :

将导致:

Emit delayed with 5 second
Emit delayed with 2 second
Emit delayed with 4 second
Emit delayed with 1 second

发射延迟 5 秒
发射延迟 2 秒
发射延迟 4 秒
发射延迟 1 秒

Note to use Thread.sleep()because delay()operates by default on the computation Scheduler

注意使用 Thread.sleep()因为delay()默认在计算调度器上运行