java - 哪个更有效,for-each 循环还是迭代器?

标签 java collections foreach

遍历集合的最有效方法是什么?

List<Integer>  a = new ArrayList<Integer>();
for (Integer integer : a) {
  integer.toString();
}

List<Integer>  a = new ArrayList<Integer>();
for (Iterator iterator = a.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   integer.toString();
}

请注意,这不是 this 的完全相同, this , this , 或 this ,尽管最后一个问题的答案之一很接近。这不是骗局的原因是,其中大多数是比较循环,您在循环内调用 get(i),而不是使用迭代器。

正如 Meta 上的建议我将发布我对这个问题的答案。

最佳答案

如果您只是在集合中徘徊以读取所有值,那么使用迭代器或新的 for 循环语法没有区别,因为新语法只是在水下使用迭代器。

但是,如果您指的是循环旧的“c 样式”循环:

for(int i=0; i<list.size(); i++) {
   Object o = list.get(i);
}

然后新的 for 循环或迭代器可能会更有效,具体取决于底层数据结构。原因是对于某些数据结构,get(i) 是一个 O(n) 操作,这使得循环成为一个 O(n2) 操作。传统的链表就是这种数据结构的一个例子。所有迭代器都有一个基本要求,即 next() 应该是 O(1) 操作,使得循环 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 循环,因为它的样板代码较少。

关于java - 哪个更有效,for-each 循环还是迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2113216/

相关文章:

java - 构造函数不能应用于给定类型,在 Java 中创建对象,面向对象编程

java - 惰性列表复制(写入时复制)

r - R foreach 循环中的负载平衡

forms - Html.BeginForm 不输出集合中第一项的表单

c# - 我如何告诉 DataContract 使用基类的 GetEnumerator?

java - 如何计算字符串中的单词数?

java - 无法确定数组中的索引

java - 为什么 Google Collections 不像 Apache Collections 那样支持 MultiKeyMap?

java - 将值存储在 Java 集合中

java - 如何指定没有输入的测试用例