Optional API vs Explicit Null Check Race

In the current article I propose to analyze what happens and how it behaves, from a performance standpoint, in case of using the Optional API feature added in JDK 8 versus the classical approach relying on explicit null checks.

In regards to this, I decided to conduct an experiment based on 3 linked classes (e.g. Outer -> Nested -> Inner) as follows:

To sum up, there is an explicit declared Outer instance which implicitly creates instances for Nested and Inner classes, links them (due to chain of constructors) and adds as a composite the intValue field to Inner.

The benchmark test measures the response time in case of getting the intValue field by iterating from Outer instance towards Inner via Nested, using Optional API approach versus the classical null checks, as per below:

As we might notice, there is a slightly better response time in case of ifComparison than optionalChain. But what really happens? To understand it better, of course we are getting back to your assembly friend :).

As per above code, we can easily spot there is no explicit null check, even if the original Java source code contains a bunch of explicit comparisons. What really happens is that Just In Time Compiler sees that all values are not null (i.e. outer != null; nested != null; inner != null) and decides to optimistically optimize them by completely removing the explicit null check (which make sense since everything is not null and the check condition always follow the same branch). But in case this assumption is not valid anymore (i.e. imagine there might be another thread that set one reference to null: outer.nested = null), the optimization is invalidated, an uncommon trap is hit and the execution switches back to the Interpreter, which slows down the performance. (i.e. see the assembly code “implicit exception: dispatches to <address>” which actually relies on SEGFAULT triggered when accessing something null, natively provided by hardware). It might be re-compiled afterwards, depending on the execution path at runtime. For more details about this kind of optimization please check the video Java performance techniques. The cost of HotSpot runtime optimizations (sections “Uncommon traps” and “Null sanity checks”).

In comparison to the previous ifComparison version, in this case the Optional API code does an explicit null check and a cast for each indirection call (e.g. Outer -> Nested -> Inner) which might be a reasonable explanation for the difference in performance between these two.

I might admit probably it is not quite significant, since it is less than 1 ns/op as spotted by this test case. However, I would encourage you to favor clean code over performance optimization tricks which might add complexity. If the case, then you can keep this in mind and if the application bottleneck comes out of this, which I doubt, then you can rely on these refined optimizations.