为何Reactor代码中的switchIfEmpty未执行?
Reactor中switchIfEmpty未执行的原因分析
问题描述
现有一段Java Reactor代码,预期逻辑如下:
- 当
filter(__ -> names.size() > 5)判断为false时,输出经过name.length() > 5过滤后的小写名称列表 - 当
filter(__ -> names.size() > 3)判断为true时,输出上述过滤列表的大写形式
但实际运行时,filter判断为true时符合预期,为false时switchIfEmpty并未执行,不符合预期。
问题代码
List<String> names = Arrays.asList("google", "abc", "fb", "stackoverflow"); Flux.fromIterable(names) .filter(name -> name.length() > 5) .collectList() .flatMap(commonAppliedFilters -> Mono.just(commonAppliedFilters) .filter(__ -> names.size() > 5) .flatMapIterable(list -> list) .map(String::toUpperCase) .collectList() .switchIfEmpty(Mono.defer(() -> Mono.just(commonAppliedFilters)))) .subscribe(System.out::println);
原因分析
问题核心在于collectList()的行为特性:
- 当
filter(__ -> names.size() > 5)返回false时,上游的Mono.just(commonAppliedFilters)被过滤掉,后续flatMapIterable没有任何元素可处理。但**collectList()在没有元素输入时,会返回一个包含空列表的Mono,而非空Mono**。 switchIfEmpty的触发条件是上游Mono完全没有发出任何元素(即空Mono),但这里上游返回的是持有空列表的非空Mono,因此switchIfEmpty的分支不会被执行,最终输出空列表,而非预期的commonAppliedFilters。
以当前代码为例:names.size()为4,filter(__ -> names.size() >5)会过滤掉commonAppliedFilters,后续collectList()生成Mono.just(Collections.emptyList()),这个Mono有明确的元素(空列表),所以switchIfEmpty不会触发。
修复方案
要让switchIfEmpty正常触发,需确保上游在过滤后无元素时返回空Mono,而非包含空列表的Mono。以下是两种可行方案:
方案一:手动判断列表是否为空,转换为空Mono
List<String> names = Arrays.asList("google", "abc", "fb", "stackoverflow"); Flux.fromIterable(names) .filter(name -> name.length() > 5) .collectList() .flatMap(commonAppliedFilters -> Mono.just(commonAppliedFilters) .filter(__ -> names.size() > 5) .flatMapIterable(list -> list) .map(String::toUpperCase) .collectList() // 若收集到空列表,转换为空Mono触发switchIfEmpty .flatMap(list -> list.isEmpty() ? Mono.empty() : Mono.just(list)) .switchIfEmpty(Mono.defer(() -> Mono.just(commonAppliedFilters)))) .subscribe(System.out::println);
方案二:简化逻辑,直接分支判断
List<String> names = Arrays.asList("google", "abc", "fb", "stackoverflow"); Flux.fromIterable(names) .filter(name -> name.length() > 5) .collectList() .flatMap(commonAppliedFilters -> { if (names.size() > 5) { return Flux.fromIterable(commonAppliedFilters) .map(String::toUpperCase) .collectList(); } else { return Mono.just(commonAppliedFilters); } }) .subscribe(System.out::println);
该方案直接通过条件判断分支处理,避免依赖switchIfEmpty的触发规则,逻辑更直观清晰。
内容的提问来源于stack exchange,提问作者Suhail
相关产品推荐
相关产品推荐

