0

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;
}
zadspecial
  • 13
  • 3

2 Answers2

4

The major reason to code like this is thread safety. Take the first example:

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

If we simply removed the local variable l and accessed last directly then a different thread to change last to be null between us checking for null and trying to access l.item, resulting in a NullPointerException.

The way it's written right here (and assuming that l.item doesn't get overwritten in some cases) this method will always either throw a NoSuchElementException or return a value that is (or at least was at some point) part of the list.

The choice to declare a local variable as final is almost entirely up to style choices, as it only affects what code the compiler will accept and not influence the actual code generation. A final local variable and an effectively-final one (i.e. one that gets assigned once and never changed after that) don't behave differently in any way.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
3

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.

ruakh
  • 175,680
  • 26
  • 273
  • 307