您现在的位置是:亿华云 > IT科技类资讯

用了那么久的 Java For 循环,你知道哪种方式效率最高吗?

亿华云2025-10-02 14:51:47【IT科技类资讯】2人已围观

简介作为程序员每天除了写很多if else之外,写的最多的也包含for循环了,都知道我们Java中常用的for循环有两种方式,一种是使用for loop,另一种是使用foreach,那如果问你,这两种方式

作为程序员每天除了写很多 if else 之外,用那写的循效率最多的也包含 for 循环了,都知道我们 Java 中常用的环知 for 循环有两种方式,一种是道种使用 for loop,另一种是最高使用 foreach,那如果问你,用那这两种方式哪一种效率最高,循效率你的环知回答是什么呢?今天阿粉就来带你看一下。

首先我们先通过代码来实际测试一下,道种在计算耗时之前我们先创建一个大小集合,最高然后通过不断的用那获取集合中的内容来测试耗时。

用了那么久的 Java For 循环,你知道哪种方式效率最高吗?

package com.example.demo;

用了那么久的 Java For 循环,你知道哪种方式效率最高吗?

import java.util.ArrayList;

用了那么久的 Java For 循环,你知道哪种方式效率最高吗?

import java.util.List;

/

**

*

* Function:

* Author:@author ziyou

* Date:2022-06-26 12:22

* Desc:无

*/

public class ForTest {

public static void main(String[] args) {

//获取一个指定大小的循效率 List 集合

Listlist = getList(1000000);

// 开启 for loop 耗时计算

long startFor = System.currentTimeMillis();

for (int i = 0; i < list.size(); i++) {

Integer integer = list.get(i);

}

long costFor = System.currentTimeMillis() - startFor;

System.out.println("for loop cost for ArrayList:" + costFor);

// forEach 耗时计算

long forEachStartTime = System.currentTimeMillis();

for (Integer integer : list) {

}

long forEachCost = System.currentTimeMillis() - forEachStartTime;

System.out.println("foreach cost for ArrayList:" + forEachCost);

}

public static ListgetList(int size) {

Listlist = new ArrayList<>();

for (int i = 0; i < size; i++) {

list.add(i);

}

return list;

}

}

简单说明一下上面的带,先创建一个 List ,环知然后通过两种方式的道种遍历来计算耗时,根据集合的最高大小不同,我们进行运行会得到下面的一些测试数据,不同人的机器上面运行的时间会不一定,不过差距应该也不会太大。云服务器提供商

size=

10000

100000

1000000

10000000

for loop

1

2

10

12

for each

1

3

17

34

通过上面的测试结果我们可以发现,在集合相对较小的情况下,for loop 和 foreach 两者的耗时基本上没有什么差别,当集合的数据量相对较大的时候,可以明显看的出来,for loop 的效率要比 foreach 的效率高。

至于为什么在大数据量的情况下 forEach 的效率要比 for 低,我们就要看下 forEach 的原理了。forEach 其实不是一种新的语法,而是一种 Java 的语法糖。在编译时,编译器会将这段代码转换成迭代器实现,并编译成字节码,我们可以再简单的看个 case,来实际看下字节码信息。

我们再编写一个简单的类,源码下载代码如下:

package com.example.demo;

import java.util.ArrayList;

import java.util.List;

/

**

*

* Function:

* Author:@author ziyou

* Date:2022-06-26 13:06

* Desc:无

*/

public class ForEachTest {

Listlist;

public void main(String[] args) {

for (Integer integer : list) {

}

}

}

通过 javac ForEachTest.java 编译成 class 文件,再通过 javap -v ForEachTest 反编译,我们就会得到下面的字节码内容:

Classfile /Users/silence/Downloads/demo/src/test/java/com/example/demo/ForEachTest.class

Last modified 2022-6-26; size 643 bytes

MD5 checksum 9cf01f7c8c87c2b4d62c39d437025b7f

Compiled from "ForEachTest.java"

public class com.example.demo.ForEachTest

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Methodref #8.#23 // java/lang/Object."":()V

#2 = Fieldref #7.#24 // com/example/demo/ForEachTest.list:Ljava/util/List;

#3 = InterfaceMethodref #25.#26 // java/util/List.iterator:()Ljava/util/Iterator;

#4 = InterfaceMethodref #27.#28 // java/util/Iterator.hasNext:()Z

#5 = InterfaceMethodref #27.#29 // java/util/Iterator.next:()Ljava/lang/Object;

#6 = Class #30 // java/lang/Integer

#7 = Class #31 // com/example/demo/ForEachTest

#8 = Class #32 // java/lang/Object

#9 = Utf8 list

#10 = Utf8 Ljava/util/List;

#11 = Utf8 Signature

#12 = Utf8 Ljava/util/List;

#13 = Utf8

#14 = Utf8 ()V

#15 = Utf8 Code

#16 = Utf8 LineNumberTable

#17 = Utf8 main

#18 = Utf8 ([Ljava/lang/String;)V

#19 = Utf8 StackMapTable

#20 = Class #33 // java/util/Iterator

#21 = Utf8 SourceFile

#22 = Utf8 ForEachTest.java

#23 = NameAndType #13:#14 // "":()V

#24 = NameAndType #9:#10 // list:Ljava/util/List;

#25 = Class #34 // java/util/List

#26 = NameAndType #35:#36 // iterator:()Ljava/util/Iterator;

#27 = Class #33 // java/util/Iterator

#28 = NameAndType #37:#38 // hasNext:()Z

#29 = NameAndType #39:#40 // next:()Ljava/lang/Object;

#30 = Utf8 java/lang/Integer

#31 = Utf8 com/example/demo/ForEachTest

#32 = Utf8 java/lang/Object

#33 = Utf8 java/util/Iterator

#34 = Utf8 java/util/List

#35 = Utf8 iterator

#36 = Utf8 ()Ljava/util/Iterator;

#37 = Utf8 hasNext

#38 = Utf8 ()Z

#39 = Utf8 next

#40 = Utf8 ()Ljava/lang/Object;

{

java.util.Listlist;

descriptor: Ljava/util/List;

flags:

Signature: #12 // Ljava/util/List;

public com.example.demo.ForEachTest();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

LineNumberTable:

line 13: 0

public void main(java.lang.String[]);

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC

Code:

stack=1, locals=4, args_size=2

0: aload_0

1: getfield #2 // Field list:Ljava/util/List;

4: invokeinterface #3, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;

9: astore_2

10: aload_2

11: invokeinterface #4, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z

16: ifeq 32

19: aload_2

20: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;

25: checkcast #6 // class java/lang/Integer

28: astore_3

29: goto 10

32: return

LineNumberTable:

line 17: 0

line 19: 29

line 20: 32

StackMapTable: number_of_entries = 2

frame_type = 252 /* append */

offset_delta = 10

locals = [ class java/util/Iterator ]

frame_type = 250 /* chop */

offset_delta = 21

}

SourceFile: "ForEachTest.java"

反编译的内容很多,不一一解释,可以看到这个字节码的一般含义是使用 getfield 命令获取变量,并调用 List.iterator 获取迭代器实例再调用 iterator.hasNext,如果返回 true,则调用 iterator.next 方法,这是迭代器遍历集合的实现逻辑。

写到这里有小伙伴就要问了,那以后遇到 List 集合我就用 for loop 了,不用 foreach了,毕竟前者的效率更好。那么接下来我们再看一个 case,这里我们把 ArrayList 换成 LinkedList,代码如下:

public static ListgetList(int size) {

Listlist = new LinkedList<>();

for (int i = 0; i < size; i++) {

list.add(i);

}

return list;

}

size=

1000

10000

100000

for loop

27

129

7654

For each

2

2

15

从上面的数据可以很明显的看到,当在处理 LinkedList 的时候,for loop 明显就慢很多了。相信具体的原因大家也知道,ArrayList 底层是基于数组结构的,网站模板所以使用 for loop 操作起来会很快,时间复杂度是 O(1),但是 LinkedList 底层是链表结构,此时如果在想通过索引来操作数据,时间复杂度将是 O (n*n)。

所以具体使用哪种循环方式以及具体需要使用哪种数据结构,都需要根据实际的业务情况来选择,任何一种方案的存在都是合理的,你小伙你们认为呢?

很赞哦!(8)