原理分析
for循环
它的实现本质上是一个出栈、改变值、比较的过程:
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
1)定义初始值i
- 2)比较初始值i < 10,如果满足则继续,否则跳出循环
- 3)执行代码块{}中的逻辑
- 4)执行i++操作
-
foreach循环
它的实现本质是把循环主体(实现了Iterator接口)转换成Iterator对象进行遍历(调用hasNext检查是否有下一个值,有则调用next获取下一个值)
// 假设有一个整型数组列表List<Integer> intList
for (Integer i : intList) {
System.out.println(i);
}
1)获取Iterator对象
- 在这里是Iterator
- 在这里是Iterator
- 2)调用hasNext()方法确认是否有下一个Integer对象,如果有则继续,否则结束循环
- 3)有则调用next()方法获取引用,并赋值给变量i
- 注:在调用next方法后,iterator将指向再下一个对象
- 4)执行代码块{}
- 5)重复执行步骤2)
while循环
- 相较之下,while循环更加灵活,它的实现与如何使用它息息相关
与for循环大致相同
int i = 0;
while (i < 10) {
System.out.println(i);
i++;
}
与foreach循环大致相同
// 假设有一个整型数组列表List<Integer> intList
Iterator<Integer> iterator = intList.iterator();
while (iterator.hasNext()) {
Integer i = (Integer) iterator.next();
// 注意:若不调用iterator.next(),可能会陷入死循环中
// iterator一直会指向第一个值,若第一个值存在,则等价于while(true) {}
System.out.println(i);
}
Stream流
- Stream流绝大多数方法的参数类型都是函数是接口,调用方法时参数一般都使用lambda表达式(因此会根据lambda表达式底层实现原理,转为内部类来实现)
- 当仅调用forEach方法执行时,其原理类似于foreach循环,将数组列表中的元素逐个遍历
// 假设有一个整型数组列表List<Integer> intList
intList.stream().forEach(i -> {
System.out.println(i);
});
// 简化写法:intList.forEach(System.out::println);
分析
- 从原理上来看,for循环和while循环的实现方式更加简洁,若追求更高的遍历效率,可以考虑使用;
- 若为数组,那么可以考虑直接使用for和while循环
- 从实现上来看,foreach和stream流的forEach实现编码量更少,因此追求用更少的代码做更多的事,可以考虑使用;
- 当然,这种选择也不是绝对的,在实际场景中,还需要考虑遍历的对象类型;比如ArrayList和LinkedList因为底层实现不同,所以其遍历效率也是不一样的)
- 会令人觉得疑惑的点是,为什么距离当前时间越近的新功能,它的遍历效率会更低?
- 我认为,随着硬件水平的提高,这种差距只会越来越小
- 大众的趋势更趋向于,使用更少的代码,解决更多的事
- 因此最近的的功能,其主要目的还是减少代码量,实现某些逻辑更简单;但相对的,这些功能的底层实现就会更加复杂。
- Tips:详细对比数据参考下面的文章,在此就不再重复写相同的东西了