To answer your first question: no, these three loops are not equivalent. Second, there is no null check to be found in these loops; there isn't any sense in trying to iterate over that which does not exist.
Assume that we have the following class:
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class EnhancedFor {
private List<Integer> dummyList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
private List<Integer> nullList = null;
public void enhancedForDummyList() {
for(Integer i : dummyList) {
System.out.println(i);
}
}
public void iteratorDummyList() {
for(Iterator<Integer> iterator = dummyList.iterator(); iterator.hasNext();) {
System.out.println(iterator.next());
}
}
public void normalLoopDummyList() {
for(int i = 0; i < dummyList.size(); i++) {
System.out.println(dummyList.get(i));
}
}
}
We're going to decompose it to its bytecode and see if there's any difference between these loops.
1: Enhanced For vs. Iterator
Here's the bytecode for the enhanced for loop.
public enhancedForDummyList()V
L0
LINENUMBER 12 L0
ALOAD 0
GETFIELD EnhancedFor.dummyList : Ljava/util/List;
INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator;
ASTORE 1
L1
FRAME APPEND [java/util/Iterator]
ALOAD 1
INVOKEINTERFACE java/util/Iterator.hasNext ()Z
IFEQ L2
ALOAD 1
INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object;
CHECKCAST java/lang/Integer
ASTORE 2
L3
LINENUMBER 13 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L4
LINENUMBER 14 L4
GOTO L1
L2
LINENUMBER 15 L2
FRAME CHOP 1
RETURN
L5
LOCALVARIABLE i Ljava/lang/Integer; L3 L4 2
LOCALVARIABLE i$ Ljava/util/Iterator; L1 L2 1
LOCALVARIABLE this LEnhancedFor; L0 L5 0
MAXSTACK = 2
MAXLOCALS = 3
Below this is the bytecode for the iterator.
public iteratorDummyList()V
L0
LINENUMBER 24 L0
ALOAD 0
GETFIELD EnhancedFor.dummyList : Ljava/util/List;
INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator;
ASTORE 1
L1
FRAME APPEND [java/util/Iterator]
ALOAD 1
INVOKEINTERFACE java/util/Iterator.hasNext ()Z
IFEQ L2
L3
LINENUMBER 25 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
GOTO L1
L2
LINENUMBER 27 L2
FRAME CHOP 1
RETURN
L4
LOCALVARIABLE iterator Ljava/util/Iterator; L1 L2 1
// signature Ljava/util/Iterator<Ljava/lang/Integer;>;
// declaration: java.util.Iterator<java.lang.Integer>
LOCALVARIABLE this LEnhancedFor; L0 L4 0
MAXSTACK = 2
MAXLOCALS = 2
Ultimately, it does look like they're doing very similar things. They're using the same interface. There is a variation in that the enhanced for loop is using two variables for the current value (i) and cursor to the rest of the list (i$), whereas the iterator only needs the cursor to invoke .next().
Similar, but not quite the same.
2. Enhanced For vs. for-Loop
Let's add in the bytecode for the for loop.
public normalLoopDummyList()V
L0
LINENUMBER 24 L0
ICONST_0
ISTORE 1
L1
FRAME APPEND [I]
ILOAD 1
ALOAD 0
GETFIELD EnhancedFor.dummyList : Ljava/util/List;
INVOKEINTERFACE java/util/List.size ()I
IF_ICMPGE L2
L3
LINENUMBER 25 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 0
GETFIELD EnhancedFor.dummyList : Ljava/util/List;
ILOAD 1
INVOKEINTERFACE java/util/List.get (I)Ljava/lang/Object;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L4
LINENUMBER 24 L4
IINC 1 1
GOTO L1
L2
LINENUMBER 27 L2
FRAME CHOP 1
RETURN
L5
LOCALVARIABLE i I L1 L2 1
LOCALVARIABLE this LEnhancedFor; L0 L5 0
MAXSTACK = 3
MAXLOCALS = 2
It's doing something different. It's not using the Iterator interface at all. Instead, we're making calls to get(), which is only specified by the List, not the Iterator.
3. Conclusion
There's a valid reason as to why the list we're dereferencing is assumed not null - we're invoking methods specified by the interface. If those methods weren't implemented that'd be different: throw an UnsupportedOperationException. If the object we're trying to invoke the contract on didn't exist - that just doesn't make sense.
arris notnullalready, would you like it to go through an extra uselessnullcheck? I suppose it is no.