对于Java中的Loop或For-each,哪个更快

打印 上一主题 下一主题

主题 880|帖子 880|积分 2640

Which is Faster For Loop or For-each in Java

对于Java中的Loop或Foreach,哪个更快
通过本文,您可以了解一些集合遍历技巧。

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

For-each不是一种新语法,而是Java的语法糖(语法糖百度百科)。在编译时,编译器将此代码转换为迭代器实现,并将其编译为字节码。我们可以通过执行命令javap-verbose-Testforeach反编译以下编译代码:
  1. public class TestForeach {
  2.     List<Integer> integers;
  3.     public void testForeach(){
  4.         for(Integer i : integers){
  5.         }
  6.     }
  7. }
复制代码
获得的详细字节码如下:
  1. public void testForeach();
  2.     descriptor: ()V
  3.     flags: ACC_PUBLIC
  4.     Code:
  5.       stack=1, locals=3, args_size=1
  6.          0: aload_0
  7.          1: getfield      #2                  // Field integers:Ljava/util/List;
  8.          4: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
  9.          9: astore_1
  10.         10: aload_1
  11.         11: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
  12.         16: ifeq          32
  13.         19: aload_1
  14.         20: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
  15.         25: checkcast     #6                  // class java/lang/Integer
  16.         28: astore_2
  17.         29: goto          10
  18.         32: return
  19.       LineNumberTable:
  20.         line 11: 0
  21.         line 13: 29
  22.         line 14: 32
  23.       LocalVariableTable:
  24.         Start  Length  Slot  Name   Signature
  25.            29       0     2     i   Ljava/lang/Integer;
  26.             0      33     0  this   Ltest/TestForeach;
  27. }
复制代码
此字节码的一般含义是使用getfileld命令来获取integers变量并且调用List.iterator来获取迭代器实例和调用iterator.hasNext。如果返回true,调用iterator.next方法。
请看,这是迭代器遍历集合的实现逻辑。
基准测试

现在让我们使用for循环方法和for-each方法进行测试。
  1. public class ForLoopTest {
  2.     public static void main(String[] args) {
  3.         List<Integer> arrayList = new ArrayList<>();
  4.         for (int i = 0; i < 10000000; i++) {
  5.             arrayList.add(i);
  6.         }
  7.         long arrayListStartTime = System.currentTimeMillis();
  8.         for (int i = 0; i < arrayList.size(); i++) {
  9.             arrayList.get(i);
  10.         }
  11.         long arrayListCost =System.currentTimeMillis()-arrayListStartTime;
  12.         System.out.println("ArrayList for loop traversal cost: "+ arrayListCost);
  13.         long arrayListForeachStartTime = System.currentTimeMillis();
  14.         for (Integer integer : arrayList) {
  15.         }
  16.         long arrayListForeachCost =System.currentTimeMillis()-arrayListForeachStartTime;
  17.         System.out.println("ArrayList foreach traversal cost: "+ arrayListForeachCost);
复制代码
这是测试结果:

如你所见,结果是显而易见的。对于ArrayList,使用For循环方法的性能优于For each方法。
我们可以说for循环比for-each好吗?
答案是否定的。在下一个基准测试中,我们将ArrayList更改为LinkedList。
同样,这里是测试结果。

原因分析

一些初学者可能想知道为什么ArrayList使用for循环方法遍历得更快,而LinkedList则更慢,速度也非常慢?
这由ArrayList和LinkedList数据结构决定。
ArrayList底层使用数组存储元素。数组是连续的内存空间。数据可以通过索引获得。时间复杂度为O(1),因此速度很快。
LinkedList的底层是一个双向链表。使用for循环实现遍历,每次都需要从链表的头节点开始。时间复杂度为O(n*n)。
结论


  • 使用ArrayList时,for循环方法更快,因为for-each由迭代器实现,并且需要执行并发修改验证。
  • 使用LinkedList时,for-each比for循环快得多,因为LinkedList是通过使用双向链表实现的。每个寻址都需要从头节点开始。如果我们需要遍历LinkedList,我们需要避免使用for循环。
  • 使用迭代器模式,for-each不需要关心集合的具体实现。如果需要替换集合,无需修改代码即可轻松替换。
欢迎关注公众号:愚生浅末。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表