如果您只是在集合中徘徊以读取所有值,那么使用迭代器或新的 for 循环语法没有区别,因为新语法只是在水下使用迭代器。
但是,如果您的意思是循环旧的“c-style”循环:
for(int i=0; i<list.size(); i++) {
Object o = list.get(i);
}
Then the new for loop, or iterator, can be a lot more efficient, depending on the underlying data structure. The reason for this is that for some data structures, get(i)
is an O(n) operation, which makes the loop an O(n2) operation. A traditional linked list is an example of such a data structure. All iterators have as a fundamental requirement that next()
should be an O(1) operation, making the loop O(n).
要验证新的 for 循环语法是否在水下使用了迭代器,请比较以下两个 Java 片段生成的字节码。首先是 for 循环:
List<Integer> a = new ArrayList<Integer>();
for (Integer integer : a)
{
integer.toString();
}
// Byte code
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 3
GOTO L2
L3
ALOAD 3
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
CHECKCAST java/lang/Integer
ASTORE 2
ALOAD 2
INVOKEVIRTUAL java/lang/Integer.toString()Ljava/lang/String;
POP
L2
ALOAD 3
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L3
其次,迭代器:
List<Integer> a = new ArrayList<Integer>();
for (Iterator iterator = a.iterator(); iterator.hasNext();)
{
Integer integer = (Integer) iterator.next();
integer.toString();
}
// Bytecode:
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 2
GOTO L7
L8
ALOAD 2
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
CHECKCAST java/lang/Integer
ASTORE 3
ALOAD 3
INVOKEVIRTUAL java/lang/Integer.toString()Ljava/lang/String;
POP
L7
ALOAD 2
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L8
正如您所看到的,生成的字节代码实际上是相同的,因此使用任何一种形式都不会造成性能损失。因此,您应该选择最美观的循环形式,对于大多数人来说,这将是 for-each 循环,因为它的样板代码较少。