Reactor未抛出NPE,是否仍为合规的Reactive Streams实现?
结论先行:Project Reactor 是完全合规的 Reactive Streams 实现,它的空值处理逻辑并没有钻规范的空子,反而在规范基础上做了更严格的防护。
先回到你提到的 Reactive Streams 规范条款:
调用onSubscribe、onNext、onError或onComplete方法时,除非传入的参数为null,否则必须正常返回;若参数为null,则必须向调用者抛出java.lang.NullPointerException。在其他情况下,Subscriber唯一合法的失败信号方式是取消其Subscription。
注意这条规范的核心约束是:当onNext等方法被传入null时,必须抛出NPE。而Reactor的处理逻辑,从根源上避免了触发这个场景——它不允许null进入响应式流中。
看你的测试代码:
第一个map返回null后,Reactor的map算子会立即校验返回值,一旦发现null,就会直接触发onError信号,而不是把null传递给下一个算子的onNext方法。你看到的日志,是因为你的subscribe只指定了onNext的回调,没有处理onError,Reactor才会用默认的错误处理逻辑打印日志(ErrorCallbackNotImplemented本质是框架提示你没有消费错误信号)。
如果给subscribe加上错误处理回调:
Mono.just("some-string") .map(this::makeNull) .map(String::toUpperCase) .subscribe( System.out::println, error -> System.err.println("捕获到错误: " + error) );
运行后就能直接捕获到NullPointerException,这说明NPE确实作为错误信号被正确发出了。
再拆解合规性:
- Reactor从未违反规范中「
onNext传入null必须抛NPE」的要求——它根本不会让null出现在onNext的参数里。 - 规范允许通过
onError传递失败信号,Reactor将空值视为非法输入,通过onError抛出NPE,完全符合规范要求。 - 你看到的日志只是框架在错误信号未被消费时的兜底处理,并非没有抛出异常。
简单说,Reactor的空值处理是「提前拦截+错误信号传递」,既满足了规范的强制要求,又额外增加了流的安全性。
内容的提问来源于stack exchange,提问作者Powet

