如何简化RxKotlin中基于另一个Observable过滤列表的代码?
优化RxJava异步过滤逻辑,告别Pair类
当然有更简洁的写法!你的核心痛点是用Pair绑定数字和校验结果,导致后续过滤、映射的代码可读性差。我们可以利用RxJava的操作符特性,直接在异步校验阶段完成过滤,完全不需要额外的配对类。
方案1:用flatMap直接处理单数字的校验与过滤
这种方式兼容所有RxJava版本,逻辑清晰易懂:
fun main() { val numberSource = NumberSource() numberSource.start() println("== started ==") numberSource.getNumberListSource() .flatMap { numberList -> Observable.fromIterable(numberList) .flatMap { number -> // 先做异步校验,只保留校验通过的结果,再映射回原数字 getOddChecker(number) .filter { it } // 仅保留校验为true的项(即偶数) .map { number } } .toList() .toObservable() } .subscribe( { println("onNext: $it") }, {}, { print("action:onComplete") } ) }
逻辑说明:
对列表中的每个数字,我们通过flatMap触发异步校验:
- 如果
getOddChecker返回true(是偶数),filter会保留这个结果,再通过map把校验结果转换回原数字; - 如果返回
false,filter会过滤掉这个结果,flatMap就不会向流中发射任何值,自然就被排除在最终列表外。
方案2:用filterWhen(RxJava 3+推荐)
如果你的项目使用RxJava 3或更高版本,filterWhen是专门为异步过滤场景设计的操作符,代码会更简洁直观:
fun main() { val numberSource = NumberSource() numberSource.start() println("== started ==") numberSource.getNumberListSource() .flatMap { numberList -> Observable.fromIterable(numberList) // 直接将异步校验的结果作为过滤条件 .filterWhen { number -> getOddChecker(number) } .toList() .toObservable() } .subscribe( { println("onNext: $it") }, {}, { print("action:onComplete") } ) }
逻辑说明:
filterWhen接收一个函数,该函数返回用于判断的Observable。当这个Observable发射true时,原数字会被保留;发射false则被过滤。完全贴合你的需求,代码几乎没有冗余,可读性拉满。
额外说明
如果需要严格保证最终列表的顺序和原列表一致,可以把flatMap替换成concatMap(两种方案都适用)。concatMap会按顺序处理每个项,而flatMap可能会并行处理导致顺序变化(不过在你的场景中,getOddChecker是同步发射结果的,所以顺序不会有问题,但如果后续校验逻辑变成真正的异步,concatMap能确保顺序)。
内容的提问来源于stack exchange,提问作者LunaVulpo
相关产品推荐
相关产品推荐

