RxJava:merge()更改发射项目的顺序?

时间:2018-07-20 09:59:47

标签: java functional-programming rx-java reactive-programming rx-java2

看看这两个小测试:

@Test
public void test1() {
    Observable.range(1, 10)
        .groupBy(v -> v % 2 == 0)
        .flatMap(group -> {
            if (group.getKey()) {
                return group;
            }
            return group;
        })
        .subscribe(System.out::println);
}

@Test
public void test2() {
    Observable.range(1, 10)
        .groupBy(v -> v % 2 == 0)
        .toMap(g -> g.getKey())
        .flatMapObservable(m -> Observable.merge(
            m.get(true),
            m.get(false)))
        .subscribe(System.out::println);
}

我期望两个都以相同的顺序返回数字列表,所以:

1 2 3 4 5 6 7 8 9 10

但第二个示例返回

2 4 6 8 10 1 3 5 7 9

相反。

在第二个示例中,merge似乎正在执行concat,实际上,如果我将其更改为concat,结果是相同的。

我想念什么?

谢谢。

1 个答案:

答案 0 :(得分:2)

基本上flatMapmerge不保证所发射物品的顺序。

来自flatMap文档:

  

请注意,FlatMap将这些Observable的发射合并在一起,以便它们可以交织。

来自merge文档:

  

合并可能会交错合并合并的Observable发出的项目(类似的运算符Concat不会交错项目,但会依次开始发射每个源Observable的所有项目,然后才开始从下一个来源Observable发射项目。

SO Answer的报价:

  

在您的情况下,对于单元素静态流,它没有任何实际的区别(但是从理论上讲,合并可能会以随机顺序输出单词,并且根据规范仍然有效)

如果您需要有保证的订单,请使用concat*

第一个示例

它是这样的:

  • 发出1时,groupBy运算符将使用键GroupedObservable创建一个false
    • flatMap将输出此可观察项中的项目-当前仅1
  • 发出2时,groupBy运算符将使用键GroupedObservable创建一个true
    • flatMap现在还将输出第二个GroupedObservable中的项目-当前为2
  • 发出3时,groupBy操作员将使用键GroupedObservable将其添加到现有的false中,flatMap将立即输出该项目
  • 发出4时,groupBy操作员将使用键GroupedObservable将其添加到现有的true中,flatMap将立即输出该项目

它可以帮助您添加更多日志记录:

    Observable.range(1, 10)
            .groupBy(v -> v % 2 == 0)
            .doOnNext(group -> System.out.println("key: " + group.getKey()))
            .flatMap(group -> {
                if (group.getKey()) {
                    return group;
                }
                return group;
            })
            .subscribe(System.out::println);

然后输出为:

key: false
1
key: true
2
3
...

第二个例子

这是完全不同的,因为toMap将阻塞直到上游完成:

  • 发出1时,groupBy运算符将使用键GroupedObservable创建一个false
    • toMap将此GroupedObservable添加到内部映射并使用键false(与GroupedObservable拥有的键相同)
  • 发出2时,groupBy运算符将使用键GroupedObservable创建一个true
    • toMap会将此GroupedObservable添加到内部地图中,并使用密钥true(与GroupedObservable拥有相同的密钥)-现在该地图有2个{ {1}}
  • 将以下数字添加到相应的GroupedObservables中,当源完成时,GroupedObservables运算符完成,并将映射传递给下一个运算符
  • toMap中,您使用地图创建了一个新的可观察对象,您首先在其中添加了偶数元素(key = {flatMapObservable),然后又添加了奇数元素(key = true

还可以在此处添加更多日志记录:

false

然后输出为:

    Observable.range(1, 10)
            .groupBy(v -> v % 2 == 0)
            .doOnNext(group -> System.out.println("key: " + group.getKey()))
            .toMap(g -> g.getKey())
            .doOnSuccess(map -> System.out.println("map: " + map.size()))
            .flatMapObservable(m -> Observable.merge(
                    m.get(true),
                    m.get(false)
            ))
            .subscribe(System.out::println);