今天看到Effective Java里面谈到foreach,for和Iterator的使用,有些疑惑,想起来之前看过一篇博客,说起了for和foreach遍历效率的区别,于是验证一番,得到如下结论。
- 对于数组而言,for和foreach遍历效率相差不大。
- 对于集合而言
- 对大多数的集合,foreach比起传统的for循环稍有性能优势但差别不大,因为它对索引的边界值只计算一次。而在对多个集合进行嵌套式迭代时优势会更明显。
- 但是测试了一下LinkedList,发现这玩意有点特殊:foreach和Iterator遍历效率相差不大(在我的机器上,测试用例用时几乎都在10,000,000纳秒左右),但是for只用了3,000,000纳秒左右)。
- Effective Java中建议,一般情况下使用foreach进行循环,因为其在简洁性和预防Bug方面有着传统for循环无法比拟的优势,并且没有性能损失。但是除了一下三种情况:
- 过滤:如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。
- 转换:如果需要遍历列表或数组,并取代它部分或者全部的元素值,就需要列表迭代器ListIterator或者数组索引,以便设定元素的值。(如果直接更改它引用对象的值的话,也可以使用Iterator,前提是符合按引用传递的原则,Iterator的元素为基本数据类型就不会按引用传递,或者它们的包装类,因为是不可变类,也不符合要求。)
- 平行迭代:如果需要并行地遍历多个集合,就需要显式的控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。
测试用例:
import java.util.*;
class Test{
private String a;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
}
public class ForAndForeach {
public static void main(String[] args) {
// double[] a = new double[10000000];
// List<Integer> a = new ArrayList<Integer>();
List<Integer> a = new LinkedList<Integer>();
// for(int i=0; i<a.length; i++){
// a[i] = Math.random()*100;
// }
for(int i=0; i<1000000; i++){
a.add(i);
}
long startTime = System.nanoTime();
// for(double s : a){
//
// }
// for(Integer s : a){
// s = "c";
// }
// for(int i=0; i<a.length; i++){
//
// }
// for(int i=0; i<a.size(); i++){
//
// }
// Iterator<Integer> it = a.iterator();
/*while(it.hasNext()){
Integer s = it.next();
}*/
for(Integer s : a){
}
long endTime = System.nanoTime();
System.out.println(endTime - startTime);
}
}