RxJava中concatMap和flatMap的区别是什么

RxJava中concatMap和flatMap的区别是什么,java,rx-java,flatmap,concatmap,Java,Rx Java,Flatmap,Concatmap,这两个函数似乎非常相似。它们具有相同的签名(接受rx.functions.Func1 正如您所写的,这两个函数非常相似,细微的区别在于如何创建输出(在应用映射函数之后) 平面贴图使用,而concatMap使用 正如您所看到的,concatMap输出序列是有序的——第一个可观察对象发出的所有项在第二个可观察对象发出的任何项之前发出, 当flatMap输出序列被合并时-被合并的可观察对象发出的项目可以以任何顺序出现,而不管它们来自哪个源可观察对象。一个非常重要的区别是:concatMap等待当前发出

这两个函数似乎非常相似。它们具有相同的签名(接受
rx.functions.Func1
正如您所写的,这两个函数非常相似,细微的区别在于如何创建输出(在应用映射函数之后)

平面贴图使用,而concatMap使用

正如您所看到的,concatMap输出序列是有序的——第一个可观察对象发出的所有项在第二个可观察对象发出的任何项之前发出,

当flatMap输出序列被合并时-被合并的可观察对象发出的项目可以以任何顺序出现,而不管它们来自哪个源可观察对象。

一个非常重要的区别是:
concatMap
等待当前发出的可观察对象完成,而
flatMap
没有。
flatMap
尝试启动t尽可能多。简单地说-你不能连接无限事物。只要确保你在
concatMap
中发出的可见光能够完成
,否则整个流程将在等待当前可见光完成以连接下一个可见光时陷入停滞。

即使这里的答案是好的,但不是无需示例即可轻松发现差异。因此,我为此创建了一个简单的示例:

@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);
}
********使用flatMap()*********

1234567981131510214

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

12345678910111313141415


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

首先,flatMap与Rxjs中的mergeMap相同。因此,这就少了一点混乱。 因此,有两个可观察到的

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

2) process_o1():process_o1()是一个函数,它将'item'作为一个参数,并对其执行某些操作,并返回一个可观察值,该值在完成时发出'done with[item]'

o1.pipe(mergeMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});
下面我们将看到:- 用风筝做的

和唐纳德分手了

《蝙蝠侠》完了

没有任何保证,凯蒂排在唐纳德之前,唐纳德排在蝙蝠侠之前。 这是因为,一旦外部可观察物发射出一个项目,内部可观察物就被激活了 订阅

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

o1.pipe(concatMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});
我们有以下顺序的保证:-

用风筝做的

和唐纳德分手了

《蝙蝠侠》完了

因为,使用concatMap操作符,在前一个内部可观测值返回之前,内部可观测值不会被订阅

外部可观测对象可以自由地继续并发出其所有值,但concatMap将确保它逐个处理这些值并保持顺序。 因此命名为concatMap

关键是,如果你热衷于维持做事的秩序,你应该使用concatMap。
但如果你不在乎顺序,你可以继续使用mergeMap,它将一次订阅所有内部观察值,并在它们返回时不断发出值。

我发现大多数被提升的答案中的示例不太清楚,所以我发布了一个有助于我理解flatMap和concatMap之间区别的示例

FlatMap从源可观测数据中获取排放量,然后创建新的可观测数据并将其合并到原始链,而concatMapconcat将其合并到原始链

主要区别在于concatMap()将合并 每个映射的可观察对象都是连续的,并一次触发一个。它只会移动到 当当前调用onComplete()时,下一个可观察到

以下是平面地图示例:

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);
}
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);
}
将导致:

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

以下是concatMap示例:

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);
}
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);
}
将导致:

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


注意使用Thread.sleep(),因为默认情况下,delay()在计算调度程序上运行

flatMap
-合并-如果发出新项,则它具有优先级

concatMap
-连接-添加到结束-发出完整序列,只有在该序列之后(上一个已完成)才能发出下一个序列


谢谢,这个解释很有帮助。根据我自己的研究,我想补充一点,一个主要的区别来自这两个函数在
merge
concat
操作符上运行的事实。在
concat
的情况下,只有在前一个完成后,才会按顺序订阅连接的观测值,而在
merge
的情况下,所有订阅都会立即进行。如果潜在的观测值是热的,这会产生很大的不同。这是一个很好的例子的补充说明:@Marek你能更新concat的链接吗?带我到一个没有提到它的页面,你的链接被破坏了。你能修复它们吗?非常清楚的例子,也就是说,如果不是
Observable.range(1,15)
,而是
Observable.of(“unique”)
,那么concatMap和flatMap将输出相同的结果。