Reactor中的onErrorContinue 和 onErrorResume
作者:十二又十三 发布时间:2022-12-01 14:30:58
前言
这似乎是 Reactor 的热门搜索之一,至少当我在谷歌中输入 onErrorContinue 时,onErrorResume 会在它旁边弹出。让我把我的测试代码和我的一些解释粘贴在下面。
1 基础功能
这是一个简单的函数,将 5 个连续的数字分别乘以 2,然后相加,当 i==2 时抛出一个异常:
public static void main(String... args) {
Flux.range(1,5)
.doOnNext(i -> System.out.println("input=" + i))
.map(i -> i == 2 ? i / 0 : i)
.map(i -> i * 2)
.reduce((i,j) -> i+j)
.doOnNext(i -> System.out.println("sum=" + i))
.block();
}
显然,输出如下:
input=1
input=2
Exception in thread "main" java.lang.ArithmeticException: / by zero
2 只有 onErrorResume ()
public static void main(String... args) {
Flux.range(1,5)
.doOnNext(i -> System.out.println("input=" + i))
.map(i -> i == 2 ? i / 0 : i)
.map(i -> i * 2)
.onErrorResume(err -> {
log.info("onErrorResume");
return Flux.empty();
})
.reduce((i,j) -> i+j)
.doOnNext(i -> System.out.println("sum=" + i))
.block();
}
输出如下:
input=1
input=2
17:40:47.828 [main] INFO com.example.demo.config.TestRunner - onErrorResume
sum=2
正如官方文档描述(onErrorResume)的那样,onErrorResume
用返回内容替换 Flux,因此在 2 之后的数据不会被处理。唯一值得一提的是,onErrorResume()
不必马上在错误之后捕获异常。在 onErrorContinue()
的官网文档中(onErrorContinue),只有 onErrorContinue()
强调了了 upstream 关键词,但显然,它还有其他含义。
3 只有 onErrorContinue()
public static void main(String... args) {
Flux.range(1,5)
.doOnNext(i -> System.out.println("input=" + i))
.map(i -> i == 2 ? i / 0 : i)
.map(i -> i * 2)
.onErrorContinue((err, i) -> {log.info("onErrorContinue={}", i);})
.reduce((i,j) -> i+j)
.doOnNext(i -> System.out.println("sum=" + i))
.block();
}
输出:
input=1
input=2
17:43:10.656 [main] INFO com.example.demo.config.TestRunner - onErrorContinue=2
input=3
input=4
input=5
sum=26
显然,onErrorContinue
会丢弃错误数据 2, 然后继续数字 3 直到 5。
4 onErrorResume() 然后 onErrorContinue()
public static void main(String... args) {
Flux.range(1,5)
.doOnNext(i -> System.out.println("input=" + i))
.map(i -> i == 2 ? i / 0 : i)
.map(i -> i * 2)
.onErrorResume(err -> {
log.info("onErrorResume");
return Flux.empty();
})
.onErrorContinue((err, i) -> {log.info("onErrorContinue={}", i);})
.reduce((i,j) -> i+j)
.doOnNext(i -> System.out.println("sum=" + i))
.block();
}
输出和上面一样:
input=1
input=2
17:47:05.789 [main] INFO com.example.demo.config.TestRunner - onErrorContinue=2
input=3
input=4
input=5
sum=26
这样的结果,你想到了吗?onErrorContinue()
会在 onErrorResume()
得到错误之前处理这个错误。当两个错误处理函数在同一个函数中的时候很明显,但是当你的函数中只有 onErrorResume()
,而一些调用者实际上有 onErrorContinue()
时,你的 onErrorResume()
没有被调用的原因可能就不那么明显了。
5 使用 onErrorResume() 模拟 onErrorContinue()
有些博客建议我们完全不用 onErrorContinue()
,且在所有场景中仅用 onErrorResume()
。但是上述示例已经展示了它们会产生不同的结果。那我们怎么实现呢?
public static void main(String... args) {
Flux.range(1,5)
.doOnNext(i -> System.out.println("input=" + i))
.flatMap(i -> Mono.just(i)
.map(j -> j == 2 ? j / 0 : j)
.map(j -> j * 2)
.onErrorResume(err -> {
System.out.println("onErrorResume");
return Mono.empty();
})
)
.reduce((i,j) -> i+j)
.doOnNext(i -> System.out.println("sum=" + i))
.block();
}
因此,本质上是将可能在 flatMap 或 concatMap 中抛出错误的操作包装起来,并在其上使用 onErrorResume()
。这样,它会产生相同的结果:
input=1
input=2
onErrorResume
input=3
input=4
input=5
sum=26
6 使用 onErrorResume() 和下游的 onErrorContinue() 模拟 onErrorContinue()
有时候,onErrorContinue() 放在调用程序中,您无法控制它。但你仍然需要 onErrorResume()。你该怎么办?
public static void main(String... args) {
Flux.range(1,5)
.doOnNext(i -> System.out.println("input=" + i))
.flatMap(i -> Mono.just(i)
.map(j -> j == 2 ? j / 0 : j)
.map(j -> j * 2)
.onErrorResume(err -> {
System.out.println("onErrorResume");
return Mono.empty();
})
.onErrorStop()
)
.onErrorContinue((err, i) -> {log.info("onErrorContinue={}", i);})
.reduce((i,j) -> i+j)
.doOnNext(i -> System.out.println("sum=" + i))
.block();
}
秘诀是在 onErrorResume() 代码块的末尾添加 onErrorStop() ——这会阻塞 onErrorContinue(),这样它就不会在 onErrorResume() 之前占用错误。尝试删除 onErrorStop(),你会看到 onErrorContinue() 在 onErrorResume 之前弹出。
来源:https://blog.csdn.net/Prepared/article/details/126473838


猜你喜欢
- 前言其实不管是哪种滑动方式,基本思想都是类似的:当点击事件传递到View时,系统记下触摸点的坐标,手指移动的时候,系统记下移动后的坐标,并计
- 在前面的文章<Mybatis配置之<properties>属性配置元素详述>,我们讲述了<properties
- 首先客户端从服务器端获取json数据1、利用HttpUrlConnection/** &nbs
- 目录场景介绍自动填充处理器Mybatis-Plus配置类配置实体类中相关字段的自动填充策略在阿里开发手册的建表规约中有说明,数据库表中应该都
- 前言前段时间一直使用到word文档转pdf或者pdf转word,寻思着用Java应该是可以实现的,于是花了点时间写了个文件转换工具源码wel
- 1、不要为抽象类提供公开的构造方法抽象类可以有构造方法,但是抽象类不能实例化。如果编程人员没有制定构造方法,编译器会自动生成一个默认的pro
- 前言倒计时功能在游戏中一直很重要, 不管是活动开放时间,还是技能冷却。 本文实现了一个通用倒计时组件,实现了倒计时的基本功能,支持倒计时结束
- 本文研究的主要是Java中后台线程的相关问题,具体介绍如下。以前从来没有听说过,java中有后台线程这种东西。一般来说,JVM(JAVA虚拟
- 今天带大家实现滑动返回效果.,具体内容如下所示:先看看效果图:因为没有具体内容,也没有简书的图片资源,所以稍微简陋了点.但是依然不妨碍我们的
- file: BluetoothEventLoop.java GB/GB2/GB3: 1. import android.os.PowerMa
- 异步,说到异步需要首先将以下同步。同步就是代码按照顺序执行,当前面的代码的请求没有正常返回结果的情况下,后面的代码是不能运行。而异步正好和这
- 概述在早期的 Java 版本中,文件 IO 操作功能一直相对较弱,主要存在以下问题:缺乏对现代文件系统的支持:只提供的基础的文件操作,不支持
- 今天工作中遇到一个需求,就是获取 excel 里面的内容,并且把 excel 另存为 csv,因为本人以前未接触过,所以下面整理出来的代码均
- 在项目开发过程中,不可避免的会升级开发工具。这次我在旧项目版本升级到新版Unity2021.2.x时,出现Visual Studio无法定位
- 在微信的运营过程中难免会出现一些无法预料的事情,比如在
- 1.下载JRebel and XRebel for Intellij插件2. 激活请查看这个文章http://www.cicoding.cn
- 在很多的Android项目中都需要用户登录、注册。这样的话在开发中做好保护用户密码的工作就显得尤为重要。这里我把自己的密码保护方法记录下来。
- 前言我们在日常的开发过程中针对一些字段采用整型的方式去代替某些具体的含义,比如性别0代表男,1代表女。如果只是一些不会变更的转译我们可以采用
- springboot 配置服务代理有时候,我们可能有下边这样的需求:即,针对于分布式服务,我们会有多种业务接口服务,但是服务器上可能只要求开
- Room在SQLite基础上做了ORM封装,使用起来类似JPA,不需要写太多的sql。导入依赖//roomdef room_version=