Reactor Flux 操作符

本文详细介绍了Reactor Flux中的一系列操作符,包括buffer、filter、window、zipWith、take、reduce、merge、flatMap、concat、concatMap以及combineLatest。通过实例展示了每个操作符的功能和使用方法,最后还探讨了这些操作符的综合应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Reactor Flux 操作符

Flux常见操作符。

1 buffer

		//每次缓存一定数量的元素到List buckets里,并push出去
        Flux.range(1, 30).buffer(20).subscribe(System.out::println);
        System.out.println("---------- 分割线1 ----------");

        //每次缓存一定数量,并跳过一定数量的元素到List buckets里,并push出去
        Flux.range(1, 30).buffer(10,10).subscribe(System.out::println);
        System.out.println("---------- 分割线2 ----------");

        //每次缓存一定数量,并跳过一定数量的元素到指定的Set buckets里,并push出去
        Flux.range(1, 30).buffer(20,20, HashSet::new).subscribe(System.out::println);
        System.out.println("---------- 分割线3 ----------");

        //指定时间内,每次缓存一定数量的元素到List buckets里,并push出去
        Flux.intervalMillis(100).bufferMillis(500).take(3).toStream().forEach(System.out::println);
        System.out.println("---------- 分割线4 ----------");

        //缓存元素到List buckets里当符合条件时,把元素push出去
        Flux.range(1, 10).bufferUntil(i -> i % 2 == 0).subscribe(System.out::println);
        System.out.println("---------- 分割线5 ----------");

        //把符合条件的缓存元素到List buckets里并把元素push出去
        Flux.range(1, 10).bufferWhile(i -> i % 2 == 0).subscribe(System.out::println);

执行结果:

---------- buffer ----------
11:02:21.193 [main] DEBUG reactor.util.Loggers$LoggerFactory - Using Slf4j logging framework
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
---------- 分割线1 ----------
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
---------- 分割线2 ----------
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
---------- 分割线3 ----------
[0, 1, 2, 3]
[4, 5, 6, 7, 8]
[9, 10, 11, 12, 13]
---------- 分割线4 ----------
[1, 2]
[3, 4]
[5, 6]
[7, 8]
[9, 10]
---------- 分割线5 ----------
[2]
[4]
[6]
[8]
[10]

2 filter

Flux.range(1, 10).filter(i -> i % 2 == 0).subscribe(System.out::println);

执行结果:

2
4
6
8
10

3 window

  • public final Flux<Flux> window(int maxSize)
//从起始位置开始将source sequence拆分成固定大小的flux
Flux<Flux<Integer>> window = Flux.range(1, 10)
        .window(3);
//subscribe1
window.subscribe(integerFlux -> {
    System.out.println("+++++分隔符+++++");
    integerFlux.subscribe(System.out::println);
});
System.out.println("---------- 分割线1 ----------");

//subscribe2
window.toStream().forEach(integerFlux -> {
    System.out.println("+++++分隔符+++++");
    integerFlux.subscribe(System.out::println);
});
System.out.println("---------- 分割线2 ----------");

执行结果:

+++++分隔符+++++
1
2
3
+++++分隔符+++++
4
5
6
+++++分隔符+++++
7
8
9
+++++分隔符+++++
10
  • public final Flux<Flux> windowMillis(long timespan)
//在一定时间内将flux sequence拆分成连接的不同的flux
Flux.intervalMillis(1)
        .windowMillis(3)
        .take(3)
        .toStream()
        .forEach(longFlux -> {
            System.out.println("+++++分隔符+++++");
            longFlux.subscribe(System.out::println);
        });

执行结果:

+++++分隔符+++++
0
1
+++++分隔符+++++
2
3
4
+++++分隔符+++++
5
6

4 zipWith

zipWith 将多个元素合并成元组,并从每个source产生元素直至结束

public final Flux<Tuple2<T, T2>> zipWith(Publisher<? extends T2> source2)

final AtomicInteger index = new AtomicInteger();
Flux<Tuple2<String, String>> tuple2Flux = Flux./just/(“a”, “b”)
        .zipWith(Flux./just/(“c”, “d”));
//subscribe1
tuple2Flux.subscribe(System./out/::println);
System./out/.println(“————— 分割线1 —————“);

//subscribe2
tuple2Flux.subscribe(tupleFlux -> {
    System./out/.println(“t1—————“ + index + “—————>+ tupleFlux.getT1());
    System./out/.println(“t2—————“ + index + “—————>+ tupleFlux.getT2());
    index.incrementAndGet();
});
System./out/.println(“————— 分割线2 —————“);

执行结果:

[a,c]
[b,d]
---------- 分割线1 ----------
t1--0-->a
t2--0-->c
t1--1-->b
t2--1-->d
---------- 分割线2 ----------

public final <T2, V> Flux zipWith(Publisher<? extends T2> source2,
final BiFunction<? super T, ? super T2, ? extends V> combinator)

Flux.just("a", "b")
        .zipWith(Flux.just("c", "d"), (s1, s2) -> String.format("%s-%s", s1, s2))
        .subscribe(System.out::println);

执行结果:

a-c
b-d

5 take

Flux.range(1, 20).take(10).subscribe(System.out::println);
Flux.range(1, 20).takeLast(10).subscribe(System.out::println);
Flux.range(1, 20).takeWhile(i -> i < 10).subscribe(System.out::println);
Flux.range(1, 20).takeUntil(i -> i == 10).subscribe(System.out::println);

6 reduce

Flux.just(1, 2, 3).reduce((x, y) -> x + y).subscribe(System.out::println);
Flux.just(1, 2, 3).reduceWith(() -> 4, (x, y) -> x + y).subscribe(System.out::println);

7 merge

//将多个源publisher中的元素合并到一个新的publisher序列中 重复的元素不会覆盖
Flux.merge(Flux.just(0, 1, 2, 3), Flux.just(7, 5, 6), Flux.just(4, 7), Flux.just(4, 7))
        .toStream()
        .forEach(System.out::print);
System.out.println();
//将多个源publisher中的元素合并到一个新的publisher序列中 重复的元素不会覆盖
//新publisher中元素的顺序为老元素的订阅顺序
Flux<Integer> flux = Flux.mergeSequential(Flux.just(9, 8, 7), Flux.just(0, 1, 2, 3),
        Flux.just(6, 5, 4));
System.out.println();
flux.sort().subscribe(System.out::print);
System.out.println();
flux.subscribe(System.out::print);
01237564747
0123456789
9870123654

8 flatmap

Flux.just(1, 2)
        .flatMap(x -> Flux.just(x * 10, 100).take(x))
        .toStream()
        .forEach(System.out::println);

9 concat

Flux.just(1, 2)
        .concat(Flux.just(5, 8))
        .toStream()
        .forEach(System.out::println);

Flux.concat(Mono.just(3), Mono.just(4), Flux.just(1, 2))
        .subscribe(System.out::println);

10 concatMap

//绑定给定输入序列的动态序列,如flatMap,但保留顺序和串联发射,而不是合并(没有交织)
Flux.just(5, 10,100)
        .concatMap(x -> Flux.just(x * 10, 100))
        .toStream()
        .forEach(System.out::println);

执行结果:

50
100
100
100
1000
100

11 combineLatest

//构建一个flux,其数据是由所有发布者最近发布的值组合而生成的
Flux.combineLatest(
        Arrays::toString,
        Flux.just(1, 3, 1, 3, 2),
        Flux.just(1, 2, 3, 4),
        Mono.just(9),
        Flux.just(5, 6),
        Flux.just(7, 8, 9)
).toStream().forEach(System.out::println);

执行结果:

[2, 4, 9, 6, 7]
[2, 4, 9, 6, 8]
[2, 4, 9, 6, 9]

12 综合应用

private static void compositeOperate() throws InterruptedException {
    Set<Integer> set = new HashSet<>();
    set.add(1);
    set.add(2);
    set.add(3);
    Flux.fromIterable(set)
            .delayElements(Duration.ofMillis(1))
            .doOnNext(FluxOperators::doSomeThing) //the callback to call on {@link Subscriber#onNext}
            .publishOn(Schedulers.elastic())
            .map(d -> d * 2)
            .take(3)
            .doOnCancel(() -> System.out.println("操作被取消了"))
            .doOnComplete(() -> System.out.println("正常结束了"))
            .onErrorResumeWith(e -> e instanceof RuntimeException, e -> {
                System.out.println("出现了 RuntimeException");
                return Flux.error(e);
            })//某种异常时才处理
            .doOnError(e -> System.out.println("出现了 Exception"))
            .doAfterTerminate(() -> System.out.println("不管正常异常,反正是结束了"))
            .onErrorReturn(444)
            .doFinally(signalType -> System.out.println("finally--->" + signalType))
            .subscribe(System.out::println);

    TimeUnit.SECONDS.sleep(5);
}


public static Integer doSomeThing(Integer integer) {
    //自行调节看效果
    if (1 != 1)
        throw new RuntimeException("a RuntimeException error");
    else if (2 != 2)
        throw new NullPointerException("a NullPointerException error");
    return integer + 1;
}

执行结果:

2
4
6
正常结束了
finally--->onComplete
不管正常异常,反正是结束了
<think>好的,用户之前让我介绍了Java中的Flux,现在又问到了Flux操作符有哪些。我需要详细整理一下这些操作符,并且分门别类,让用户更容易理解。首先,我得回忆一下Flux的常用操作符,可能需要分成转换类、过滤类、组合类、错误处理、背压控制、异步处理等等。 用户可能是刚开始学习反应式编程,或者在使用Spring WebFlux时遇到了需要处理数据流的情况。他们可能已经了解了Flux的基本概念,现在需要更深入的操作方法,以便在实际项目中应用。因此,我需要确保解释清晰,每个操作符的功能和示例都要明确,避免使用过于专业的术语,但又要准确。 接下来,我需要考虑用户可能的使用场景。比如,处理HTTP请求流、数据库查询结果、或者消息队列中的数据。不同的场景可能需要不同的操作符组合,例如转换数据格式、过滤无效数据、合并多个流、处理异常等。因此,在分类操作符时,要考虑到这些实际应用情况,帮助用户快速找到需要的功能。 另外,用户可能对某些操作符的区别不太清楚,比如map和flatMap,或者concat和merge的区别。这时候需要在解释时特别指出这些区别,用简单的示例说明它们的不同效果。同时,错误处理部分也很重要,特别是在异步环境下,如何处理异常,避免程序崩溃,这也是用户关心的问题。 在结构上,我应该先分大类,每个大类下列举常用的操作符,每个操作符给出功能描述和代码示例。这样用户查阅起来方便,也便于理解各个操作符的作用。最后,可能还需要一个总结,提示用户如何选择合适的操作符,以及学习路径,比如结合Spring WebFlux实践。 需要确保代码示例正确且简洁,避免复杂的逻辑,让用户能够快速看到操作符的效果。同时,注意背压相关的操作符,因为这是反应式编程中的一个重要概念,用户可能在处理高负载数据流时需要用到这些来控制数据流速。 最后,检查是否有遗漏的重要操作符,比如常用的take、delayElements、zip等,确保覆盖全面。同时,避免信息过载,保持每个部分的解释简洁明了,重点突出。这样用户能够逐步深入学习,而不是被过多的信息淹没。</think>在 Project Reactor 的 `Flux` 中,**操作符(Operators)** 是处理数据流的核心工具,提供了丰富的函数式方法用于转换、过滤、组合和异步控制流。以下是常见操作符的分类及示例: --- ### **一、转换类操作符** 用于对数据流中的元素进行转换或映射。 1. **`map`** 同步转换元素,一对一映射。 ```java Flux.just("a", "b", "c") .map(String::toUpperCase) // 转为大写 .subscribe(System.out::println); // 输出 A, B, C ``` 2. **`flatMap`** 异步转换元素,一对多映射(返回新的 `Flux`)。 ```java Flux.just("apple", "banana") .flatMap(s -> Flux.fromArray(s.split(""))) // 拆分为字符流 .subscribe(System.out::println); // 输出 a,p,p,l,e,b,a,n,a,n,a ``` 3. **`concatMap`** 类似 `flatMap`,但保持顺序(按原始顺序拼接结果流)。 4. **`cast`** 强制类型转换。 ```java Flux.just(1, 2, 3) .cast(Number.class) // 转为 Number 类型 ``` --- ### **二、过滤类操作符** 用于筛选或限制数据流中的元素。 1. **`filter`** 根据条件过滤元素。 ```java Flux.range(1, 5) .filter(i -> i % 2 == 0) // 保留偶数 .subscribe(System.out::println); // 输出 2,4 ``` 2. **`take`** 取前 N 个元素。 ```java Flux.range(1, 10) .take(3) // 取前3个 .subscribe(System.out::println); // 输出 1,2,3 ``` 3. **`skip`** 跳过前 N 个元素。 ```java Flux.range(1, 5) .skip(2) // 跳过1,2 .subscribe(System.out::println); // 输出 3,4,5 ``` 4. **`distinct`** 去重。 ```java Flux.just(1, 2, 2, 3) .distinct() // 去重 .subscribe(System.out::println); // 输出 1,2,3 ``` --- ### **三、组合类操作符** 用于合并多个数据流或处理流间关系。 1. **`merge`** 合并多个流(按元素到达顺序,不保证原始顺序)。 ```java Flux<Integer> flux1 = Flux.range(1, 3); Flux<Integer> flux2 = Flux.range(4, 2); Flux.merge(flux1, flux2).subscribe(); // 输出 1,2,3,4,5 ``` 2. **`concat`** 按顺序拼接流(先消费完第一个流,再处理第二个)。 ```java Flux.concat(flux1.delayElements(Duration.ofMillis(100)), flux2) .subscribe(); // 先输出 flux1 的元素,再输出 flux2 ``` 3. **`zip`** 将多个流的元素按位置配对组合。 ```java Flux.zip(Flux.just("A", "B"), Flux.just(1, 2)) .subscribe(tuple -> System.out.println(tuple.getT1() + tuple.getT2())); // 输出 A1, B2 ``` 4. **`combineLatest`** 合并多个流的最新元素(任一流发射新值时触发)。 ```java Flux.combineLatest( flux1, flux2, (v1, v2) -> v1 + "-" + v2 ).subscribe(); ``` --- ### **四、错误处理操作符** 用于处理流中的异常。 1. **`onErrorReturn`** 发生错误时返回默认值。 ```java Flux.error(new RuntimeException("Oops")) .onErrorReturn("Fallback") .subscribe(System.out::println); // 输出 Fallback ``` 2. **`onErrorResume`** 发生错误时切换到一个备用流。 ```java Flux.error(new RuntimeException()) .onErrorResume(e -> Flux.just("Recovered")) .subscribe(System.out::println); // 输出 Recovered ``` 3. **`retry`** 重试订阅(可指定次数)。 ```java Flux.error(new RuntimeException()) .retry(2) // 最多重试2次 .onErrorReturn("Failed"); ``` --- ### **五、背压控制操作符** 管理消费者处理速度与生产者速度的平衡。 1. **`onBackpressureBuffer`** 缓冲溢出元素(默认无界)。 ```java flux.onBackpressureBuffer(10) // 缓冲区大小10 .subscribe(...); ``` 2. **`onBackpressureDrop`** 丢弃无法处理的新元素。 ```java flux.onBackpressureDrop(dropped -> log.warn("Dropped: {}", dropped)); ``` --- ### **六、异步与调度操作符** 控制数据流的执行线程。 1. **`subscribeOn`** 指定订阅时的调度器(如异步线程池)。 ```java Flux.range(1, 3) .subscribeOn(Schedulers.boundedElastic()) .subscribe(...); // 在弹性线程池执行 ``` 2. **`publishOn`** 切换后续操作的调度器。 ```java flux.publishOn(Schedulers.parallel()) .map(...) // 在并行线程池执行 ``` --- ### **七、实用工具操作符** 其他常用操作。 1. **`log`** 打印流的事件日志(调试用)。 ```java flux.log().subscribe(); ``` 2. **`delayElements`** 延迟发射每个元素。 ```java Flux.just("a", "b") .delayElements(Duration.ofSeconds(1)) // 每隔1秒发射 .subscribe(); ``` 3. **`then`** 流结束后执行操作(不传递数据)。 ```java Flux.just(1, 2) .then(() -> Mono.just("Done")) .subscribe(System.out::println); // 输出 Done ``` --- ### **总结** - **选择操作符的逻辑**:根据需求选择操作符,例如: - 转换数据 → `map`/`flatMap` - 过滤 → `filter`/`take` - 组合流 → `merge`/`zip` - 错误恢复 → `onErrorResume` - **进阶学习**:掌握 `Schedulers`(线程池控制)、`window`(窗口分组)、`groupBy`(按条件分组)等高级操作符。 - **实战建议**:在 Spring WebFlux 中结合 REST API 或响应式数据库驱动(如 R2DBC)实践。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值