Is it a good practice to define final local variable when I want to use class field in class method in Java?

Viewed 103

Recently, I'm reading Java Source Code, e.g. ArrayList, ArrayDeque, LinkedList, etc. I found when they want to use some class field in class method, they will always declare a final local variable which equals to the field. However, if I haven't read the source code, I will never consider doing this thing. Is it a good practice to do so? Or why does Java Source Code choose to do so? What's the advantage, like the performance?

Reference:

LinkedList source code

ArrayList source code

ArrayDeque source code

Example: getFirst() in LinkedList

public E getFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

boolean delete(int i) in ArrayDeque

    private boolean delete(int i) {
        checkInvariants();
        final Object[] elements = this.elements;
        final int mask = elements.length - 1;
        final int h = head;
        final int t = tail;
        final int front = (i - h) & mask;
        final int back  = (t - i) & mask;

        // Invariant: head <= i < tail mod circularity
        if (front >= ((t - h) & mask))
            throw new ConcurrentModificationException();

        // Optimize for least element motion
        if (front < back) {
            if (h <= i) {
                System.arraycopy(elements, h, elements, h + 1, front);
            } else { // Wrap around
                System.arraycopy(elements, 0, elements, 1, i);
                elements[0] = elements[mask];
                System.arraycopy(elements, h, elements, h + 1, mask - h);
            }
            elements[h] = null;
            head = (h + 1) & mask;
            return false;
        } else {
            if (i < t) { // Copy the null tail as well
                System.arraycopy(elements, i + 1, elements, i, back);
                tail = t - 1;
            } else { // Wrap around
                System.arraycopy(elements, i + 1, elements, i, mask - i);
                elements[mask] = elements[0];
                System.arraycopy(elements, 1, elements, 0, t);
                tail = (t - 1) & mask;
            }
            return true;
        }
    }
1 Answers

This is a micro-optimisation which probably makes sense for standard library code which is going to be used by lots and lots of people and read by significantly fewer people. I wouldn't recommend doing this in your own code unless performance is a real concern and you've profiled your application to determine which parts of the code are the real bottlenecks, since otherwise the performance gain is likely to be negligible, so the main effect will be to make your code more verbose.

Using local variables should have some very minor performance benefits, because:

  • Local variables will be allocated either on the stack or in registers, which are faster to access than other memory, so doing only a single field access from the heap definitely minimises the number of slower accesses (at best, accessing memory on the heap can only be as fast as accessing a local variable, but at worst it can be slower).
  • The bytecode instructions for accessing local variables are shorter. The first four local variables can be loaded using aload0, aload1, aload2 and aload3, which are a single byte each, and aload is two bytes including an index to the local variable to be loaded. In comparison, getfield takes three bytes, two of which are used to reference the field being accessed.

There is also potentially a semantic difference in non-synchronised methods, since the local variable will hold the same value even if the field is changed by another thread during the method execution. However, most of the standard library classes you'll see this pattern in are not meant to be thread-safe, and even if the class is meant for concurrency, doing this doesn't necessarily make the method thread-safe anyway.

Related