Java 中 for 和 foreach 哪个性能高?

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

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

package com.example.demo;import java.util.ArrayList;
import java.util.List;public class ForTest {public static void main(String[] args) {//获取一个指定大小的 List 集合List<Integer> list = 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 List<Integer> getList(int size) {List<Integer> list = new ArrayList<>();for (int i = 0; i < size; i++) {list.add(i);}return list;}}

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

size=10000100000100000010000000
for loop121012
for each131734

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

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

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

package com.example.demo;import java.util.ArrayList;
import java.util.List;/*** <br>* <b>Function:</b><br>* <b>Author:</b>@author ziyou<br>* <b>Date:</b>2022-06-26 13:06<br>* <b>Desc:</b>无<br>*/
public class ForEachTest {List<Integer> list;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.classLast modified 2022-6-26; size 643 bytesMD5 checksum 9cf01f7c8c87c2b4d62c39d437025b7fCompiled from "ForEachTest.java"
public class com.example.demo.ForEachTestminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #8.#23         // java/lang/Object."<init>":()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<Ljava/lang/Integer;>;#13 = Utf8               <init>#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        // "<init>":()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.List<java.lang.Integer> list;descriptor: Ljava/util/List;flags:Signature: #12                          // Ljava/util/List<Ljava/lang/Integer;>;public com.example.demo.ForEachTest();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 13: 0public void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLICCode:stack=1, locals=4, args_size=20: aload_01: getfield      #2                  // Field list:Ljava/util/List;4: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;9: astore_210: aload_211: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z16: ifeq          3219: aload_220: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;25: checkcast     #6                  // class java/lang/Integer28: astore_329: goto          1032: returnLineNumberTable:line 17: 0line 19: 29line 20: 32StackMapTable: number_of_entries = 2frame_type = 252 /* append */offset_delta = 10locals = [ 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 List<Integer> getList(int size) {List<Integer> list = new LinkedList<>();for (int i = 0; i < size; i++) {list.add(i);}return list;}
size=100010000100000
for loop271297654
For each2215

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

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

e5a815cb365f1140a3131ee39e251f7d.gif

往期推荐

05da16d8a5a020b7155f1f364e548552.jpeg

如何优雅的写 Controller 层代码?


93c7675bc8fd072d0cb2c444c4ba1e8d.jpeg

一个依赖搞定Spring Boot 配置文件脱敏


72b77500463f0b98b8a2a15cefe0b867.jpeg

面试突击58:truncate、delete和drop的6大区别!


e9bc6babf14fb3098c85f54c640a963c.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里出品,SpringBoot自动化部署神器!

最近发现一款阿里出品的IDEA插件CloudToolkit&#xff0c;不仅支持直接打包应用部署到远程服务器上&#xff0c;而且还能当终端工具使用。试用了一把这个插件&#xff0c;非常不错&#xff0c;推荐给大家&#xff01;装上这个插件&#xff0c;IDEA一站式开发又近了一步&#xf…

聊聊异步编程的 7 种实现方式

最近有很多小伙伴给我留言&#xff0c;能不能总结下异步编程&#xff0c;今天就和大家简单聊聊这个话题。早期的系统是同步的&#xff0c;容易理解&#xff0c;我们来看个例子同步编程当用户创建一笔电商交易订单时&#xff0c;要经历的业务逻辑流程还是很长的&#xff0c;每一…

二进制补码乘法除法_二进制乘法和除法

二进制补码乘法除法1)二进制乘法 (1) Binary Multiplication) Binary numbers can be multiplied using two methods, 二进制数可以使用两种方法相乘&#xff0c; Paper method: Paper method is similar to multiplication of decimal numbers on paper. 纸张方法&#xff1a…

控制JSP头部引入外部文件编译后在第一行

2019独角兽企业重金招聘Python工程师标准>>> 一.错误引入方法 假设当前需要在JSP页面输出xml格式数据&#xff0c;需要引入以下外部文件&#xff0c;通过以下的方式来引入则无法正常输出数据&#xff1a; 访问页面会报错误&#xff1a;xml的声明不在文档的第一行 看…

4种常见的缓存模式,你都知道吗?

概述 在系统架构中&#xff0c;缓存可谓提供系统性能的最简单方法之一&#xff0c;稍微有点开发经验的同学必然会与缓存打过交道&#xff0c;最起码也实践过。如果使用得当&#xff0c;缓存可以减少响应时间、减少数据库负载以及节省成本。但如果缓存使用不当&#xff0c;则可能…

面试突击63:distinct 和 group by有什么区别?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在 MySQL 中&#xff0c;最常见的去重方法有两个&#xff1a;使用 distinct 或使用 group by&#xff0c;那它们有什…

从20s优化到500ms,我用了这三招

前言接口性能问题&#xff0c;对于从事后端开发的同学来说&#xff0c;是一个绕不开的话题。想要优化一个接口的性能&#xff0c;需要从多个方面着手。本文将接着接口性能优化这个话题&#xff0c;从实战的角度出发&#xff0c;聊聊我是如何优化一个慢查询接口的。上周我优化了…

面试拆解:系统上线后CPU急速飙升,该怎么排查?

上次面试官问了个问题&#xff1a;应用上线后Cpu使用率飙升如何排查&#xff1f;其实这是个很常见的问题&#xff0c;也非常简单&#xff0c;那既然如此我为什么还要写呢&#xff1f;因为上次回答的时候我忘记将线程PID转换成16进制的命令了。所以我决定再重温一遍这个问题&…

MySQL 死锁了,怎么办?

作者&#xff1a;小林coding提纲如下&#xff1a;正文有个业务主要逻辑就是新增订单、修改订单、查询订单等操作。然后因为订单是不能重复的&#xff0c;所以当时在新增订单的时候做了幂等性校验&#xff0c;做法就是在新增订单记录之前&#xff0c;先通过 select ... for upda…

10 张图搞懂服务注册发现机制

在微服务架构或分布式环境下&#xff0c;服务注册与发现技术不可或缺&#xff0c;这也是程序员进阶之路必须要掌握的核心技术之一&#xff0c;本文通过图解的方式带领大家轻轻松松掌握。引入服务注册与发现组件的原因先来看一个问题&#xff0c;假如现在我们要做一个商城项目&a…

ASP.NET 5 Beta8 已经发布

Microsoft ASP.NET and Web Tools 2015 (Beta8) http://www.microsoft.com/en-us/download/details.aspx?id49442 .net core 完成了98%&#xff0c;绝大部分类库完成了跨平台开发&#xff0c;已经基本可用&#xff0c;下一版本为RC&#xff0c;发布时间为12月&#xff0c;将可…

面试突击65:HTTPS有什么优点?说一下它的执行流程?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;说到 HTTPS 相信大部分人都是不陌生&#xff0c;因为目前我们使用的绝大数网站都是基于 HTTPS 的&#xff0c;比如以…

Cell.reuseIdentifier 指什么

Cell.reuseIdentifier 指的是 默认为空&#xff0c;如果不定义&#xff0c;在执行 [_tableView registerNib:templateCellNib forCellReuseIdentifier:_templateCell.reuseIdentifier]; 时&#xff0c;提示 must pass a valid reuse identifier to -[UITableView registerNib:f…

缓存穿透、缓存雪崩、缓存击穿?

背景 在现代软件架构中&#xff0c;缓存的应用已经非常普及。缓存的使用在面试和实践中都是避不开的硬技能、硬知识&#xff0c;如果你说还不太熟悉缓存的使用&#xff0c;可能都不好意思说自己是程序员。这篇文章&#xff0c;带大家进一步学习在缓存使用中不得不考虑三个特殊场…

如何防止订单重复支付?

大家好&#xff0c;我是磊哥&#xff0c;想必大家对在线支付都不陌生&#xff0c;今天和大家聊聊如何防止订单重复支付。看看订单支付流程我们来看看&#xff0c;电商订单支付的简要流程&#xff1a;订单钱包支付流程从下单/计算开始&#xff1a;下单/结算&#xff1a;这一步虽…

3 分钟快速上手 Spring 事件机制

小伙伴们好呀~ 今天来和大家分享下这个 Spring事件机制内容概览image-20210829132019387原理image-20210828184103069这个熟悉 观察者模式 的小伙伴应该一眼就看出来啦~其实就是个简单版的 发布-订阅模式有三个核心类&#x1f447;事件 ApplicationEvent事件发布器 Application…

mis dss gis_MIS中的决策支持系统(DSS)

mis dss gisThe Decision Support System is always helpful to management people to take decisions/decisions and finds the key business insights from available information systems. 决策支持系统始终有助于管理人员做出决策/决策&#xff0c;并从可用的信息系统中找到…

使用Grunt构建自动化开发环境

1、准备工作 1&#xff09;首页确保电脑上网&#xff0c;以及能够访问https://registry.npmjs.org/&#xff0c;因需从此网站中下载安装相应的插件; 2&#xff09;电脑安装Node.js&#xff0c;Grunt及Grunt插件都是基于node.js运行的&#xff1b;如果你电脑上未装node.js&#…

面试突击66:请求转发和请求重定向有什么区别?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在 Java 中&#xff0c;跳转的实现方式有两种&#xff1a;请求转发和请求重定向&#xff0c;但二者是完全不同的&…

99%的Java程序员会踩的6个坑

前言作为Java程序员的你&#xff0c;不知道有没有踩过一些基础知识的坑。有时候&#xff0c;某个bug&#xff0c;你查了半天&#xff0c;最后发现竟然是一个非常低级的错误。有时候&#xff0c;某些代码&#xff0c;这一批数据功能正常&#xff0c;但换了一批数据就出现异常了。…