I’ve been looking at at some of the java primitive collections (trove, fastutil, hppc) and I’ve noticed a pattern that class variables are sometimes declared as final local variables. For example:
public void forEach(IntIntProcedure p) {
final boolean[] used = this.used;
final int[] key = this.key;
final int[] value = this.value;
for (int i = 0; i < used.length; i++) {
if (used[i]) {
p.apply(key[i],value[i]);
}
}
}
I’ve done some benchmarking, and it appears that it is slightly faster when doing this, but why is this the case? I’m trying to understand what Java would do differently if the first three lines of the function were commented out.
Note: This seems similiar to this question, but that was for c++ and doesn’t address why they are declared final.
The
finalkeyword is a red herring here.The performance difference comes because they are saying two different things.
is saying, “fetch a boolean array, and for each element of that array do something.”
Without
final boolean[] used, the function is saying “while the index is less than the length of the current value of theusedfield of the current object, fetch the current value of theusedfield of the current object and do something with the element at indexi.”The JIT might have a much easier time proving loop bound invariants to eliminate excess bound checks and so on because it can much more easily determine what would cause the value of
usedto change. Even ignoring multiple threads, ifp.applycould change the value ofusedthen the JIT can’t eliminate bounds checks or do other useful optimizations.