Java响应式流中非受检异常可直接传播并终止流,受检异常必须包装为非受检异常(如RuntimeException)才能使用;异常触发onError后流立即终止,需用onErrorResume等操作符实现容错恢复。

Java 中的 ReactStream 并不是标准 Java 或 Reactor/Reactive Streams 规范中的官方类——你很可能指的是 Project Reactor(如 Mono 或 Flux)或基于 Reactive Streams 规范的流(如 org.reactivestreams.Publisher)。在这些响应式流中,非受检异常(unchecked exceptions,如 RuntimeException 及其子类)可以被直接传递并终止流;而受检异常(checked exceptions)则不能直接抛出,必须包装处理。
非受检异常天然支持传递
Reactor 和 Reactive Streams 规范明确允许 onError 信号携带任意 Throwable,但仅限于 非受检异常(即继承自 RuntimeException 或 Error 的类型)。这类异常无需显式声明,可在 map、flatMap、filter 等操作符中直接 throw:
-
✅ 正确示例:
Flux.just(1, 2, 0).map(i -> 10 / i)会因ArithmeticException(运行时异常)触发onError,下游可捕获处理 -
❌ 错误做法: 在 lambda 中直接 throw
IOException(受检异常)会导致编译失败,因为函数式接口(如Function)不声明 throws
受检异常必须转为非受检异常
若业务逻辑中必须抛出受检异常(如调用传统 IO 方法),需主动将其包装为非受检异常才能进入流:
- 使用
RuntimeException包装:throw new RuntimeException(e) - 更推荐使用
Exceptions.propagate(e)(来自 Reactor 工具类)或SneakyThrows(Lombok)避免冗余 try-catch - 也可自定义工具方法:
static <T> T sneakyThrow(Throwable t) { throw (RuntimeException) t; }(需确保传入的是非受检异常或已包装)
异常传播与错误处理策略
非受检异常发出后,默认会终止流。如需容错,应显式使用错误恢复操作符:
立即学习“Java免费学习笔记(深入)”;
-
onErrorResume():替换异常为新流(如返回默认值) -
onErrorReturn():返回单个备用元素 -
retry()或retryWhen():按条件重试 -
doOnError():仅做副作用(如日志),不改变流行为
注意 onError 信号的不可逆性
一旦 onError 被发出,该流生命周期结束,后续所有操作符(包括 map、filter)不再执行。因此:
- 异常应在真正无法恢复时才传播,避免过早中断
- 不要在
doOnError里试图“吞掉”异常而不恢复 —— 这不会让流继续 - 若需部分失败容忍,考虑用
flatMap+ 单个元素流封装,使每个子流独立错误处理


















