Java异常性能开销主要来自Throwable构造时fillInStackTrace()遍历栈帧,正常try-catch无成本;高频路径、底层库等场景应避免用异常做流程控制。
会,但仅在异常被抛出并实际构建堆栈时产生显著开销;正常 try-catch 结构本身几乎无成本。
关键在于 Throwable 构造时默认调用 fillInStackTrace() —— 它会遍历当前线程所有栈帧,生成完整堆栈信息。这个操作是同步、反射式、且与栈深度强相关的,耗时可能达微秒到毫秒级(尤其在深调用链或高并发场景)。
try-catch 不抛异常:零运行时开销(JIT 编译后基本消除)throw new RuntimeException():触发 fillInStackTrace(),开销明显throw new RuntimeException().fillInStackTrace(null)(不推荐):跳过堆栈收集,但会丢失调试信息fillInStackTrace() 返回 this:可规避,但需谨慎评估可观测性损失高频路径、底层库、序列化/反序列化循环、网络协议解析等对延迟敏感的代码中,用异常做流程控制(如“找不到就抛异常再捕获”)极易成为瓶颈。
Map.get(key) 后判 null 再抛异常,应改用 Map.getOrDefault(key, defaultValue) 或先 containsKey()
JsonProcessingException:建议预校验或使用可选字段 API(如 Jackson 的 @JsonInclude(JsonInclude.Include.NON_ABSENT))SQLException 判断主键冲突:应优先用 INSERT ... ON CONFLICT DO NOTHING(PostgreSQL)或 INSERT IGNORE(MySQL),避免触发异常路径
如果确实需要记录错误现场但不依赖完整堆栈,可用更轻量方式替代 new Exception()。
Thread.currentThread().getStackTrace() 手动截取前几帧(例如只取最外层 3 层),避免全栈遍历%throwable{short}(Logback)或 %xEx{1}(Log4j2),限制打印深度public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message, null, false, false); // suppressFillInStackTrace = true
}
}真正影响性能的不是“有没有 try-catch”,而是“有没有在热路径上频繁 throw”。很多团队优化了半天 GC,却在 DAO 层每查一次数据库都抛一次 NoResultException——这种地方改一行代码比调 JVM 参数实在得多。