Creating an exception object is not more expensive than creating other regular objects. The main cost is hidden in native fillInStackTrace
method which walks through the call stack and collects all required information to build a stack trace: classes, method names, line numbers etc.
The myth about high exception costs comes from the fact that most of Throwable
constructors implicitly call fillInStackTrace
. However, there is one constructor to create a Throwable
without a stack trace. It allows you to make throwables that are very fast to instantiate. Another way to create lightweight exceptions is to override fillInStackTrace
.
Now what about throwing an exception?
In fact, it depends on where a thrown exception is caught.
If it is caught in the same method (or, more precisely, in the same context, since the context can include several methods due to inlining), then throw
is as fast and simple as goto
(of course, after JIT compilation).
However if a catch
block is somewhere deeper in the stack, then JVM needs to unwind the stack frames, and this can take significantly longer. It takes even longer, if there are synchronized
blocks or methods involved, because unwinding implies releasing of monitors owned by removed stack frames.
I could confirm the above statements by proper benchmarks, but fortunately I don't need to do this, since all the aspects are already perfectly covered in the post of HotSpot's performance engineer Alexey Shipilev: The Exceptional Performance of Lil' Exception.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…