在RxJava中concatMap和flatMap有什么区别

时间:2014-07-04 09:51:27

标签: rx-java flatmap concatmap

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

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

6 个答案:

答案 0 :(得分:48)


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

平面地图使用merge operator,而concatMap使用concat operator

如您所见,concatMap输出序列是有序的 - 第一个Observable发出的所有项目都是在第二个Observable发出的任何项目之前发出的, 当flatMap输出序列合并时 - 合并的Observable发出的项可以按任何顺序出现,无论它们来自哪个源Observable。

答案 1 :(得分:12)

一个非常重要的区别:concatMap等待当前发出的observable完成,而flatMap没有。flatMapconcatMap尝试尽可能多地开始。简单地说 - 你无法连接无限的东西。 只需确保您在loadData中发出的可观察量可以完成,否则整个流程将停滞等待当前的observable完成以连接下一个。

答案 2 :(得分:7)

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

@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()*********

     

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

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

答案 3 :(得分:7)

我发现大多数投票答案中的示例不太清楚,因此我发布了一个示例,帮助我理解了flatMap和concatMap之间的区别。

FlatMap从可观察的源中获取排放,然后创建新的可观察并合并到原始链,而concatMap concat 到原始链。

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

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

将导致:

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

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

将导致:

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

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

答案 4 :(得分:0)

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

1)o1:((['Kitty','Donald','Batman'])

中的物品的简单列表

2)process_o1():process_o1()是一个将参数“ item”作为参数并对其进行处理并返回Observable的函数,该Observable在完成时发出“与[item]完成”。

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

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

与唐纳德完成。

与蝙蝠侠完成。

不保证凯蒂(Kitty)在唐纳德(Donald)之前,唐纳德(Donald)在蝙蝠侠(Batman)之前。 这是因为,一旦外部可观察物发射出一个项目,内部可观察物即为 已订阅。

=== 但是如果使用concatMap:-

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

我们保证以下顺序:-

与Kity完成。

与唐纳德完成。

与蝙蝠侠完成。

因为使用concatMap运算符,内部Observable在先前的内部Observable返回之前没有被订阅。

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

在症结所在,如果您热衷于维护服务的顺序,则应该使用concatMap。 但是,如果您不关心顺序,则可以继续使用mergeMap,它将立即订阅所有内部Observable并在它们返回时继续发出值。

答案 5 :(得分:0)

flatMap 与 concatMap

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

concatMap - 连接 - 添加到最后 - 发出完整序列,只有在那之后(前一个完成)才能发出下一个序列

[map vs flatMap]