原理分析

for循环

  • 它的实现本质上是一个出栈、改变值、比较的过程:

    1. for (int i = 0; i < 10; i++) {
    2. System.out.println(i);
    3. }
  • 1)定义初始值i

  • 2)比较初始值i < 10,如果满足则继续,否则跳出循环
  • 3)执行代码块{}中的逻辑
  • 4)执行i++操作
  • 5)重新执行步骤2)

    foreach循环

  • 它的实现本质是把循环主体(实现了Iterator接口)转换成Iterator对象进行遍历(调用hasNext检查是否有下一个值,有则调用next获取下一个值)

    1. // 假设有一个整型数组列表List<Integer> intList
    2. for (Integer i : intList) {
    3. System.out.println(i);
    4. }
  • 1)获取Iterator对象

    • 在这里是Iterator
  • 2)调用hasNext()方法确认是否有下一个Integer对象,如果有则继续,否则结束循环
  • 3)有则调用next()方法获取引用,并赋值给变量i
    • 注:在调用next方法后,iterator将指向再下一个对象
  • 4)执行代码块{}
  • 5)重复执行步骤2)

while循环

  • 相较之下,while循环更加灵活,它的实现与如何使用它息息相关
  • 与for循环大致相同

    1. int i = 0;
    2. while (i < 10) {
    3. System.out.println(i);
    4. i++;
    5. }
  • 与foreach循环大致相同

    1. // 假设有一个整型数组列表List<Integer> intList
    2. Iterator<Integer> iterator = intList.iterator();
    3. while (iterator.hasNext()) {
    4. Integer i = (Integer) iterator.next();
    5. // 注意:若不调用iterator.next(),可能会陷入死循环中
    6. // iterator一直会指向第一个值,若第一个值存在,则等价于while(true) {}
    7. System.out.println(i);
    8. }

Stream流

  • Stream流绝大多数方法的参数类型都是函数是接口,调用方法时参数一般都使用lambda表达式(因此会根据lambda表达式底层实现原理,转为内部类来实现)
  • 当仅调用forEach方法执行时,其原理类似于foreach循环,将数组列表中的元素逐个遍历
    1. // 假设有一个整型数组列表List<Integer> intList
    2. intList.stream().forEach(i -> {
    3. System.out.println(i);
    4. });
    5. // 简化写法:intList.forEach(System.out::println);

分析

  • 从原理上来看,for循环和while循环的实现方式更加简洁,若追求更高的遍历效率,可以考虑使用;
    • 若为数组,那么可以考虑直接使用for和while循环
  • 从实现上来看,foreach和stream流的forEach实现编码量更少,因此追求用更少的代码做更多的事,可以考虑使用;
  • 当然,这种选择也不是绝对的,在实际场景中,还需要考虑遍历的对象类型;比如ArrayList和LinkedList因为底层实现不同,所以其遍历效率也是不一样的)
  • 会令人觉得疑惑的点是,为什么距离当前时间越近的新功能,它的遍历效率会更低?
    • 我认为,随着硬件水平的提高,这种差距只会越来越小
    • 大众的趋势更趋向于,使用更少的代码,解决更多的事
    • 因此最近的的功能,其主要目的还是减少代码量,实现某些逻辑更简单;但相对的,这些功能的底层实现就会更加复杂。
  • Tips:详细对比数据参考下面的文章,在此就不再重复写相同的东西了

参考