For循环或Foreach,Java中哪个更快?

For循环或Foreach,Java中哪个更快?

For循环或Foreach,Java中哪个更快?

有同事曾经问我一个问题是我们是否应该使用 for 或 forEach 遍历 ArrayList?

关于 forEach 和 for 之间争论并不新鲜。我的印象是 forEach 更快。

1.5 版中引入的 forEach 循环(或增强的 for 循环)通过完全隐藏迭代器或索引变量避免编码中的错误。

for(int i = 0; i < mylist.length; i++) {
 if(i < 5) {
 //do something
 } else {
 //do other stuff
 }
}

但是,我们可以使用 foreach 创建一个单独的int 变量。例如:

整数索引 = -1;

int index = -1;
for(int myint : mylist) {
 index++;
 if(index < 5) {
 //do something
 } else {
 //do other stuff
 }
}

让我们编写一个简单的类,它具有 foreachTest() 方法,该方法使用 forEach 迭代列表

import java.util.List;

public class ForEachTest {
        List intList;
        
    public void foreachTest(){
        for(Integer i : intList){

        }
    }
}

当我们编译这个类时,编译器会在内部将此代码转换为迭代器实现。我通过执行javap -verbose IterateListTest对编译后的代码进行了反编译。

public void foreachTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=3, args_size=1
         0: aload_0
         1: getfield      #19                 // Field intList:Ljava/util/List;
         4: invokeinterface #21,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
         9: astore_2
        10: goto          23
        13: aload_2
        14: invokeinterface #27,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        19: checkcast     #33                 // class java/lang/Integer
        22: astore_1
        23: aload_2
        24: invokeinterface #35,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
        29: ifne          13
        32: return
      LineNumberTable:
        line 9: 0
        line 12: 32
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      33     0  this   Lcom/greekykhs/springboot/ForEachTest;
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 13
          locals = [ class com/greekykhs/springboot/ForEachTest, top, class java/util/Iterator ]
          stack = []
        frame_type = 9 /* same */

从上面的字节码中,我们可以看到,

a)getfield 命令用于获取变量整数。

b调用 List.iterator 以获取迭代器实例

c)调用iterator.hasNext,如果返回true,调用iterator.next方法。

让我们做一个性能测试。在 IterateListTest 的 main 方法中,创建了一个列表并使用 for 和 forEach 循环对其进行迭代。

import java.util.ArrayList;
import java.util.List;

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

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

        long forLoopTraversalCost =System.currentTimeMillis()-forLoopStartTime;
        System.out.println("for loop traversal cost for ArrayList= "+ forLoopTraversalCost);

        long forEachStartTime = System.currentTimeMillis();
        for (Integer integer : mylist) {}

        long forEachTraversalCost =System.currentTimeMillis()-forEachStartTime;
        System.out.println("foreach traversal cost for ArrayList= "+ forEachTraversalCost);
        }
}

结果如下:

For循环或Foreach,Java中哪个更快?

for循环的性能要好于forEach。现在,让我们使用 LinkedList 而不是 ArrayList。可以看到 forEach 对于 LinkedList 的性能更好。

ArrayList 在内部使用数组来存储元素。由于数组是连续的内存空间,数据是通过索引检索的,时间复杂度为 O(1)。

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

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

相关文章

推荐文章