我读到增强的for循环比正常的 for loop 更有效:
http://developer.android.com/guide/practices/performance.html#foreach
当我搜索它们的效率之间的差异时,我发现的是:在正常循环的情况下,我们需要额外的步骤来找出数组的长度或大小等。
for(Integer i : list){
....
}
int n = list.size();
for(int i=0; i < n; ++i){
....
}
但这是唯一的原因,增强的for循环优于正常循环吗?在这种情况下,最好使用普通的 for循环,因为理解增强的 for loop 有点复杂。
请检查此问题:http://www.coderanch.com/t/258147/java-programmer-SCJP/certification/Enhanced-Loop-Vs-Loop
任何人都可以解释这两种for循环的内部实现,或解释使用增强 for循环的其他原因吗?
答案 0 :(得分:51)
说增强的for循环更有效,这有点过于简单了。 可以,但在很多情况下,它几乎与老派循环完全相同。
首先要注意的是,对于集合,增强的for循环使用Iterator
,因此如果您使用Iterator
手动迭代集合,那么您应该具有与增强了循环。
增强的for循环比天生实现的传统循环更快的地方是这样的:
LinkedList<Object> list = ...;
// Loop 1:
int size = list.size();
for (int i = 0; i<size; i++) {
Object o = list.get(i);
/// do stuff
}
// Loop 2:
for (Object o : list) {
// do stuff
}
// Loop 3:
Iterator<Object> it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
// do stuff
}
在这种情况下,循环1将比循环2和循环3都慢,因为它必须(部分地)在每次迭代中遍历列表以找到位置i
处的元素。然而,由于使用Iterator
,循环2和3将仅在列表中进一步步骤一个元素。循环2和3也具有几乎相同的性能,因为循环3几乎就是编译器在循环2中编写代码时将产生的内容。
答案 1 :(得分:8)
我对自己今天做的一个小实验感到很惊讶。
所以我所做的是我将一定数量的元素插入链表并使用上面提到的三种方法迭代它1)使用高级for循环2)使用Iterator 3)使用简单循环和get()
我想像你们这样的程序员可以通过查看代码来更好地理解我的所作所为。
long advanced_timeElapsed,iterating_timeElapsed,simple_timeElapsed;
long first=System.nanoTime();
for(Integer i: myList){
Integer b=i;
}
long end= System.nanoTime();
advanced_timeElapsed=end-first;
System.out.println("Time for Advanced for loop:"+advanced_timeElapsed);
first=System.nanoTime();
Iterator<Integer> it = myList.iterator();
while(it.hasNext())
{
Integer b=it.next();
}
end= System.nanoTime();
iterating_timeElapsed=end-first;
System.out.println("Time for Iterating Loop:"+iterating_timeElapsed);
first=System.nanoTime();
int counter=0;
int size= myList.size();
while(counter<size)
{
Integer b=myList.get(counter);
counter++;
}
end= System.nanoTime();
simple_timeElapsed=end-first;
System.out.println("Time for Simple Loop:"+simple_timeElapsed);
结果不是我所期望的。以下是3例中经过的时间图。
Y轴时间已过
X轴测试案例
测试案例1:10输入
测试案例2:30输入
测试案例3:50输入
测试用例4:100输入
测试用例5:150输入
测试用例6:300输入
测试用例7:500输入
测试用例8:1000输入
测试案例9:2000输入
测试案例10:5000输入
测试用例11:10000输入
测试用例12:100000输入
在这里你可以看到简单的循环比其他循环更好。如果你在上面的代码中发现任何错误,请回复,我会再次检查。在我仔细检查字节码后,我会进一步了解这一点,看看幕后发生了什么。 我为这么长的回应道歉,但我喜欢描述性的。 菲利普
答案 2 :(得分:7)
我读到增强的for循环比循环的正常效率高。
实际上有时它对程序的效率较低,但大部分时间都完全相同。
对开发人员来说效率更高,这通常更为重要
for-each循环在迭代集合时特别有用。
List<String> list =
for(Iterator<String> iter = list.iterator(); list.hasNext(); ) {
String s = list.next();
更容易编写为(但是同样的东西,所以它对程序来说效率不高)
List<String> list =
for(String s: list) {
使用索引访问随机访问的集合时,使用“旧”循环会稍微提高效率。
List<String> list = new ArrayList<String>(); // implements RandomAccess
for(int i=0, len = list.size(); i < len; i++) // doesn't use an Iterator!
在集合上使用for-each循环总是使用Iterator,对随机访问列表的效率稍差。
AFAIK,使用for-each循环对于程序来说永远不会更有效,但正如我所说,开发人员的效率通常更重要。
答案 3 :(得分:3)
for-each使用Iterator接口。我怀疑它比“旧”风格更有效。迭代器还需要检查列表的大小。
这主要是为了提高可读性。
对于像LinkedList这样的非随机访问集合应该更快,但是这种比较是不公平的。无论如何,你不会习惯于第二次实现(使用慢速索引访问)。
答案 4 :(得分:3)
foreach循环和这种循环一样有效:
for (Iterator<Foo> it = list.iterator(); it.hasNext(); ) {
Foo foo = it.next();
...
}
因为它完全等同。
如果使用
迭代列表int size = list.size();
for (int i = 0; i < size; i++) {
Foo foo = list.get(i);
...
}
然后foreach循环将具有与循环相同的性能,但仅适用于ArrayList 。在LinkedList的情况下,你的循环将具有糟糕的性能,因为在每次迭代时,它必须遍历列表的所有节点,直到它到达i
元素。
foreach循环(或基于迭代器的循环,它是相同的),没有这个问题,因为迭代器保持对当前节点的引用,并在每次迭代时简单地转到下一个。这是最好的选择,因为它适用于所有类型的列表。它也更清楚地表达了意图,并且更安全,因为你没有冒险在循环内增加索引,或者在嵌套循环的情况下使用错误的索引。
答案 5 :(得分:0)
来自Effective Java:
循环遍历数组的标准习惯用语不一定会导致 冗余检查。现代JVM实现可以优化它们。
但Josh Bloch没有描述JVM如何优化它们。
答案 6 :(得分:0)
所有答案都很好,我认为不需要更多答案,但我只想指出:
增强的for语句可以仅使用obtain array elements
无法 使用到modify elements
。
如果您的计划需要修改元素,请使用传统的counter-controlled for
语句。
看看
int[] array = { 1, 2, 3, 4, 5 };
for (int counter = 0; counter < array.length; counter++)
array[counter] *= 2;
我们无法使用enhanced for
语句,因为我们是modifying the array’s elements
。