You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构造异常实例是否比构造异常Supplier实例的性能开销更高?

Java Optional中orElseThrow写法问题解答

首先给出两种写法的代码对照:

// 正确写法
var value = getOptional().orElseThrow(NullPointerException::new);
// 错误写法,无法通过编译
var value = getOptional().orElseThrow(new NullPointerException());

为什么必须使用传入方法引用的写法?

1. 语法层面的硬性要求

Optional.orElseThrow 从Java 8首次引入开始,就只提供两种重载:

  • 无参版本:空值时直接抛出NoSuchElementException
  • 单参版本:仅接收Supplier<? extends Throwable>类型的参数,用来自定义抛出的异常类型

不存在直接接收异常实例作为参数的重载,因此第二种写法本身就不符合Java语法规范,编译阶段就会报错,根本无法运行。

2. 延迟加载的性能合理性

即使不考虑语法问题,直接传入异常实例的逻辑也存在严重的性能浪费:
直接写new NullPointerException()时,异常实例会在orElseThrow方法调用前就被创建完成,不管getOptional()返回的Optional是否有值,这个创建过程的开销都会被触发。
而传入NullPointerException::new这个Supplier实现时,只有当Optional确实为空、需要抛出异常的时候,才会调用Supplier的get()方法创建异常实例,Optional有值的场景下完全不会产生额外开销,这个逻辑和orElse、orElseGet的差异是完全一致的。

创建异常实例的开销是否比Supplier实例更高?

答案是前者开销远高于后者,核心差异来自两者的创建逻辑:

  • 异常实例创建时,JVM会自动生成当前线程的完整栈追踪信息,需要遍历整个调用栈采集类名、方法名、行号等全量栈帧数据,是非常重的操作,哪怕创建后不抛出,开销也已经产生。
  • 而NullPointerException::new属于无上下文捕获的方法引用,对应的Supplier是无状态的轻量函数对象,JVM可以对其做逃逸分析、实例缓存等多层优化,极端场景下甚至可以完全消除对象创建的开销,整体开销和异常创建相比几乎可以忽略。

内容的提问来源于stack exchange,提问作者Bogdan Tischenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 12:15:02