Java – Which part of throwing an Exception is expensive


In Java, using throw/catch as a part of logic when there's not actually an error is generally a bad idea (in part) because throwing and catching an exception is expensive, and doing it many times in a loop is usually far slower than other control structures which don't involve throwing exceptions.

My question is, is the cost incurred in the throw/catch itself, or when creating the Exception object (since it gets a lot of runtime information including the execution stack)?

In other words, if I do

Exception e = new Exception();

but don't throw it, is that most of the cost of throwing, or is the throw + catch handling what's costly?

I'm not asking whether putting code in a try/catch block adds to the cost of executing that code, I'm asking whether catching the Exception is the expensive part, or creating (calling the constructor for) the Exception is the expensive part.

Another way of asking this is, if I made one instance of Exception and threw and caught it over and over, would that be significantly faster than creating a new Exception every time I throw?

Best Solution

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.