Search code examples
javaoopfinalinstance-variableslocal-variables

Why is a (final) local variable declared when using an instance variable in Java?


Consider this code I found from the LinkedList class in the JDK.

public E getLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return l.item;
}

First question: Why is this seemingly redundant local variable l declared in this code? From what I see, we could've simply used last instead.


In the next code from the HashMap class, the same thing is done. The local variable tab is declared to be to equal to the instance variable table.

Second question: Why is final not used here with tab like it was used in the previous code?

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

Solution

  • First question: Why is this seemingly redundant local variable l declared in this code? From what I see, we could've simply used last instead.

    I can think of two likely reasons:

    • Although LinkedList is not intended to be threadsafe, it's still preferable for it to behave consistently when that doesn't conflict with any more important goals (such as performance). If 'getLast()' referred twice to 'last', it would be possible for 'last' to be null the second time, triggering a NullPointerException instead of the desired NoSuchElementException.

      • This accords with LinkedList's support for ConcurrentModificationException — a best-effort attempt to detect bugs, but no actual threadsafety guarantees.
    • Performance:

      • A local variable access may be slightly faster: Java local vs instance variable access speed
      • Using a local variable may make it clearer to the optimizer that it can store this reference in a register and reuse it, without having to re-check the value of 'last'. (Technically the Java Memory Model would already let it do this, but it's possible that not all versions of the JVM are smart enough to do so, or perhaps even some versions intentionally don't, for whatever reason.)

      JDK classes take performance very seriously, because they're incredibly widely used, and because they're "close friends" with the JVM.

    In either case, please be aware that JDK code doesn't really reflect Java best practices for mainstream code; it's interesting to think about these decisions, but please don't be tempted to emulate them!

    Second question: Why is final not used here with tab like it was used in the previous code?

    I doubt there's a particular reason here; there would be no downsides to using final.