请考虑以下情形。
List<String> list = new ArrayList<>();
现在我添加了此列表的String
值。
我使用以下方法来查看列表中的每个元素。
选项一 - 使用for-each
for (String i : list) {
System.out.println(i);
}
选项二 - 使用Iterator
Iterator it=list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
我只想知道如果我使用for-each
代替Iterator
,是否有任何性能优势。现在在Java中使用Iterator也是一种不好的做法吗?
答案 0 :(得分:85)
for-each
是使用iterators
的语法糖(方法2)。
如果需要在循环中修改集合,则可能需要使用iterators
。第一种方法会抛出异常。
for (String i : list) {
System.out.println(i);
list.remove(i); // throws exception
}
Iterator it=list.iterator();
while (it.hasNext()){
System.out.println(it.next());
it.remove(); // valid here
}
答案 1 :(得分:16)
差别主要是语法糖,除了Iterator可以从正在迭代的Collection中删除项目。从技术上讲,增强的for循环允许你遍历任何可迭代的东西,它至少包括集合和数组。
不要担心性能差异。这种微观优化是一种无关紧要的分心。如果您需要随时删除项目,请使用迭代器。否则for循环往往更常用,因为它们更具可读性,即:
for (String s : stringList) { ... }
VS
for (Iterator<String> iter = stringList.iterator(); iter.hasNext(); ) {
String s = iter.next();
...
}
答案 2 :(得分:9)
for-each
是一个高级循环结构。在内部,它创建一个迭代器并迭代Collection。在for-each
构造上使用实际Iterator对象的唯一好处是,您可以使用Iterator的方法(如.remove()
)修改您的集合。迭代时不使用迭代器方法修改集合将产生ConcurrentModificationException.
答案 3 :(得分:3)
最好的方法是在java 8中,
list.forEach(System.out::println);
以下是一些有用的链接。
答案 4 :(得分:2)
简单答案:不,不。
for-each
循环在内部创建Iterator
来迭代整个集合。
明确使用Iterator
的好处是您可以访问Iterator
方法。
答案 5 :(得分:0)
如果您想要替换列表中的项目,我会带着for循环去旧学校
for (int nIndex=0; nIndex < list.size(); nIndex++) {
Obj obj = (Obj) list.get(nIndex);
// update list item
list.set(nIndex, obj2);
}
答案 6 :(得分:0)
foreach
无论如何都使用了引擎盖下的迭代器。它真的只是语法糖。
考虑以下计划:
import java.util.List;
import java.util.ArrayList;
public class Whatever {
private final List<Integer> list = new ArrayList<>();
public void main() {
for(Integer i : list) {
}
}
}
让我们用javac Whatever.java
编译它,
并使用main()
:
javap -c Whatever
的反汇编字节码
public void main();
Code:
0: aload_0
1: getfield #4 // Field list:Ljava/util/List;
4: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
9: astore_1
10: aload_1
11: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
16: ifeq 32
19: aload_1
20: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
25: checkcast #8 // class java/lang/Integer
28: astore_2
29: goto 10
32: return
我们可以看到foreach
编译成一个程序:
List.iterator()
Iterator.hasNext()
:调用Iterator.next()
并继续循环至于&#34;为什么这个无用的循环不会从编译的代码中优化出来?我们可以看到它没有对列表项做任何事情&#34;:嗯,您可以对您的迭代进行编码,使.iterator()
有副作用,或者{ {1}}会产生副作用或产生有意义的后果。
您可以很容易地想象,表示来自数据库的可滚动查询的迭代可能会在.hasNext()
上做一些戏剧性的事情(比如联系数据库,或关闭游标,因为您已达到结果集的末尾) )。
所以,尽管我们可以证明循环体中没有任何反应......但是,当我们迭代时,证明没有任何有意义/重要的事情会更加昂贵(难以处理?)。编译器必须将这个空循环体留在程序中。
我们希望的最好的是编译器警告。有趣的是.hasNext()
没有警告我们这个空循环体。但IntelliJ IDEA确实如此。不可否认,我已将IntelliJ配置为使用Eclipse编译器,但这可能不是原因。
答案 7 :(得分:0)
以下是一个简单的代码段,用于检查For-each
vs Iterator
vs for
在Java版本8上执行ArrayList<String>
遍历的性能。< /强>
long MAX = 2000000;
ArrayList<String> list = new ArrayList<>();
for (long i = 0; i < MAX; i++) {
list.add("" + i);
}
/**
* Checking with for each iteration.
*/
long A = System.currentTimeMillis();
for (String data : list) {
// System.out.println(data);
}
long B = System.currentTimeMillis();
System.out.println(B - A + "ms");
/**
* Checking with Iterator method
*/
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
// System.out.println(iterator.next());
}
long C = System.currentTimeMillis();
System.out.println(C - B + "ms");
/**
* Checking with normal iteration.
*/
for (int i = 0; i < MAX; i++) {
list.get((int) (i % (MAX - i)));
// System.out.println(list.get(i));
}
long D = System.currentTimeMillis();
System.out.println(D - C + "ms");
平均输出值
19ms
9ms
27ms
结果分析:
Iterator
(9毫秒)&lt;For-each
(19毫秒)&lt;For
(27ms)此处
Iterator
的效果最佳,而For
的效果最差。但For-each
表现介于两者之间。