handle 是 Reactor 中一个非常灵活的操作符,它允许你对每个源元素进行处理,并可以选择性地发出零个或多个元素。它既可以用于映射(map)也可以用于过滤(filter),因此可以看作是 map 和 filter 的组合。
1. handle 是一个实例方法
handle是一个实例方法,这意味着它必须链接在一个现有的源(如Flux或Mono)上使用,与其他操作符(如map、filter、flatMap)类似。- 例如:
Flux<String> alphabet = Flux.just(-1, 30, 13, 9, 20).handle((i, sink) -> {String letter = alphabet(i);if (letter != null) {sink.next(letter);}});
2. handle 的签名
-
handle的签名是:Flux<R> handle(BiConsumer<T, SynchronousSink<R>>); -
它接收一个
BiConsumer,第一个参数是当前的源元素T,第二个参数是SynchronousSink<R>,用于向下游发送处理后的结果。
3. handle 的作用
handle允许你对每个源元素进行处理,并可以选择性地发出零个或多个元素。- 它既可以用于映射(map)也可以用于过滤(filter),因此可以看作是
map和filter的组合。 - 例如,你可以使用
handle来实现一个“映射 + 过滤 null”的场景,就像mapNotNull在 Kotlin 中一样。
4. handle 与 map 和 filter 的区别
map:只用于映射,不进行过滤。如果映射函数返回null,Reactor 会抛出NullPointerException。filter:只用于过滤,不进行映射。如果过滤条件不满足,元素会被丢弃。handle:结合了map和filter的功能,可以灵活处理元素,甚至可以抛出异常或忽略元素。
5. 示例:handle 用于“映射 + 过滤 null”
- 你提到的
alphabet方法有时会返回null,但你希望只保留非null的结果。 - 使用
handle可以安全地处理这种情况,避免NullPointerException。
Flux<String> alphabet = Flux.just(-1, 30, 13, 9, 20).handle((i, sink) -> {String letter = alphabet(i);if (letter != null) {sink.next(letter);}});
alphabet.subscribe(System.out::println);
-
输出:
M I T -
解释:
-1和30超出范围,返回null,因此不会调用sink.next()。13、9、20在范围内,返回字母M、I、T,并被发送到下游。
6. handle 的优势
- 灵活性:可以同时处理映射、过滤、错误处理等复杂逻辑。
- 安全性:可以避免
NullPointerException,因为你可以显式检查返回值是否为null。 - 性能:
handle是一个轻量级操作符,适合处理简单的映射和过滤逻辑。
7. handle 与 mapNotNull 的关系
- 在 Kotlin 中,
mapNotNull是一个专门用于“映射 + 过滤 null”的操作符。 - 在 Reactor 中,虽然没有
mapNotNull,但handle可以实现类似的功能。 - 例如,你可以使用
handle来替代mapNotNull,尤其是在需要处理复杂逻辑时。
8. 总结
handle是 Reactor 中一个非常灵活的操作符,它允许你对每个源元素进行处理,并可以选择性地发出零个或多个元素。- 它既可以用于映射(map)也可以用于过滤(filter),因此可以看作是
map和filter的组合。 - 在处理可能返回
null的映射函数时,handle是一个安全且灵活的选择,可以避免NullPointerException,并提供更细粒度的控制。
参考资料
handle是一个实例方法,可以链接在现有源上,用于处理每个元素。handle接收一个BiConsumer,用于处理每个元素并决定是否发送到下游。handle可以用于“映射 + 过滤 null”的场景,避免NullPointerException。