七爪源码:java中的for循环或foreach哪个更快

通过这篇文章你可以得到一些集合遍历的技巧。

七爪源码:java中的for循环或foreach哪个更快

Java 有两种遍历集合的方式。 一个是最基本的for-loop,另一个是jdk5引入的for-each。 使用这种方法,我们可以更方便地遍历数组和集合。 但是你有没有想过这两种方法? 哪一个更有效地遍历集合?


for-each 实现原理

Foreach 不是一种新语法,而是 Java 的语法糖。 在编译时,编译器会将此代码转换为迭代器实现,并将其编译为字节码。 我们可以通过执行命令javap -verbose Testforeach 来反编译下面的编译代码

public class TestForeach {
    List integers;
    public void testForeach(){
        for(Integer i : integers){

        }
    }
}

得到的详细字节码如下:

public void testForeach();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=3, args_size=1
         0: aload_0
         1: getfield      #2                  // Field integers:Ljava/util/List;
         4: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
         9: astore_1
        10: aload_1
        11: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
        16: ifeq          32
        19: aload_1
        20: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        25: checkcast     #6                  // class java/lang/Integer
        28: astore_2
        29: goto          10
        32: return
      LineNumberTable:
        line 11: 0
        line 13: 29
        line 14: 32
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           29       0     2     i   Ljava/lang/Integer;
            0      33     0  this   Ltest/TestForeach;
}

这个字节码的一般含义是使用getfield命令获取变量整数并调用List.iterator获取迭代器实例并调用iterator.hasNext。 如果返回 true,则调用 iterator.next 方法。 看,这是迭代器遍历集合的实现逻辑。


基准测试

现在让我们使用 for-loop 方法和 for-each 方法来测试。

public class ForLoopTest {

    public static void main(String[] args) {
        List arrayList = new ArrayList<>();
        for (int i = 0; i < 10000000; i++) {
            arrayList.add(i);
        }

        long arrayListStartTime = System.currentTimeMillis();
        for (int i = 0; i < arrayList.size(); i++) {
            arrayList.get(i);
        }

        long arrayListCost =System.currentTimeMillis()-arrayListStartTime;
        System.out.println("ArrayList for loop traversal cost: "+ arrayListCost);

        long arrayListForeachStartTime = System.currentTimeMillis();
        for (Integer integer : arrayList) {

        }

        long arrayListForeachCost =System.currentTimeMillis()-arrayListForeachStartTime;
        System.out.println("ArrayList foreach traversal cost: "+ arrayListForeachCost);

以下是测试结果。

七爪源码:java中的for循环或foreach哪个更快

如您所见,结果是显而易见的。 对于 ArrayList,使用 for-loop 方法的性能优于 for-each 方法。 我们可以宣布 for 循环获胜吗? 答案是否定的。在下一个基准测试中,我们将 ArrayList 更改为 LinkedList。

同样,这是测试结果。

七爪源码:java中的for循环或foreach哪个更快

原因分析

有的初学者可能会奇怪,为什么ArrayList使用for循环的方式遍历速度更快,而LinkedList又慢又很慢呢?这是由 ArrayList 和 LinkedList 数据结构决定的。

ArrayList 底层使用数组来存储元素。数组是连续的内存空间。可以通过索引获取数据。时间复杂度为 O(1),所以速度很快。

LinkedList 的底层是双向链表。使用for循环实现遍历,每次都需要从链表的头节点开始。时间复杂度为 O (n*n)。


结论

  1. 使用ArrayList时for循环方法更快,因为for-each是由迭代器实现的,需要进行并发修改校验。
  2. 使用 LinkedList 时,for-each 比 for-loop 快得多,因为 LinkedList 是使用双向链表实现的。每个寻址都需要从头节点开始。如果我们需要遍历LinkedList,我们需要避免使用for循环。
  3. 使用迭代器模式,for-each 不需要关心集合的具体实现。如果需要更换集合,无需修改代码即可轻松更换。

最后,感谢您的阅读,期待您的关注和阅读更多有趣的文章。


关注七爪网,获取更多APP/小程序/网站源码资源!

更快   源码   for
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章