Java中Exception构造开销大,因fillInStackTrace()同步采集栈轨迹,比普通对象创建慢10–100倍;应避免用异常作控制流、循环内新建异常,优先用if判断或复用静态异常,自定义异常可重写fillInStackTrace()跳过栈采集。
Java中Exception构造本身就有明显开销
每次新建Exception对象,JVM都会采集当前线程的栈轨迹(stack trace),调用Throwable.fillInStackTrace()——这个操作是同步且昂贵的,尤其在高并发或高频路径上。实测显示,构造一个Exception比普通对象创建慢10–100倍,取决于栈深度。
常见误用场景:
- 用
new RuntimeException("xxx")做控制流(比如校验失败时抛出再捕获) - 在循环内反复构造异常(如解析CSV时每行都
new ParseException()) - 自定义异常未重写
fillInStackTrace(),却声称“轻量”
优化建议:
- 对已知可预期的错误(如参数为空、格式不符),优先用
if判断 + 返回错误码/封装Optional/Result类,避免抛异常 - 若必须抛异常,复用静态异常实例(仅适用于不带上下文信息、无栈需求的场景,如
public static final IllegalArgumentException ILLEGAL_ARG = new IllegalArgumentException();) - 自定义异常时,在构造函数中显式调用
super(null)并重写fillInStackTrace()返回this,可跳过栈采集(注意:这样会导致printStackTrace()无堆栈,仅适用于内部状态机等可控场景)
try-catch块本身不拖慢性能,但catch分支执行有代价
JVM对try块的编译处理已很成熟:只要没真正抛出异常,try-catch的字节码和纯代码几乎无差异。瓶颈永远在“异常被抛出并被捕获”那一瞬间——即throw触发栈展开(stack unwinding)+ catch块内逻辑执行。
立即学习“Java免费学习笔记(深入)”;
典型陷阱: