一.起因

由于最近业务的数据量和复杂度有点高,所有对效率这方便需要格外重视,不然代码是写完了,效率太低了,代码中使用到了非常多的循环,所以我折腾了几种循环的性能问题

二.对几种常见的做法进行分析

  1. 这里先附上测试代码
package com.xx.controller;import com.xx.entity.Department;
import com.xx.entity.User;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;/*** @author aqi* DateTime: 2020/8/19 9:42 上午* Description: No Description*/
public class Demo {public static void main(String[] args) {List<User> userList = new ArrayList<>();for (int i = 0; i < 1000000; i++) {User user = new User();user.setId(i);user.setName("name:" + i);String departmentId = i % 3 == 1 ? "1000" : (i % 3 == 2 ? "2000" : "3000");user.setDepartmentId(departmentId);userList.add(user);}List<Department> departmentList = new ArrayList<>();departmentList.add(new Department("1000", "部门1"));departmentList.add(new Department("2000", "部门2"));departmentList.add(new Department("3000", "部门3"));long start1 = System.currentTimeMillis();// 增强for// O(n * n)for (User user : userList) {for (Department department : departmentList) {if (Objects.equals(user.getDepartmentId(), department.getId())) {user.setDepartmentName(department.getDepartmentName());break;}}}long end1 = System.currentTimeMillis();System.out.println("增强for耗时:" + (end1 - start1));// 普通for// O(n * n)for (int i = 0; i < userList.size(); i++) {for (int j = 0; j < departmentList.size(); j++) {if (Objects.equals(userList.get(i).getDepartmentId(), departmentList.get(j).getId())) {userList.get(i).setDepartmentName(departmentList.get(j).getDepartmentName());break;}}}long end2 = System.currentTimeMillis();System.out.println("普通for耗时:" + (end2 - end1));// 第一种stream写法,这个时间复杂度是O(n*n)// O(n * n)userList.forEach(e -> departmentList.forEach(ex -> {if (Objects.equals(e.getDepartmentId(), ex.getId())) {e.setDepartmentName(ex.getDepartmentName());}}));long end3 = System.currentTimeMillis();System.out.println("第一种stream写法耗时:" + (end3 - end2));// 第二种stream写法O(n + n + 1) = O(n)// O(n)Map<String, Department> collect = departmentList.stream().collect(Collectors.toMap(Department::getId, Function.identity()));// O(n)userList.forEach(e -> {// O(1)Department department = collect.get(e.getDepartmentId());e.setDepartmentName(department.getDepartmentName());});long end4 = System.currentTimeMillis();System.out.println("第二种stream写法耗时:" + (end4 - end3));}}
  1. 查看测试结果
  • 1w条数据

  • 10w条数据

  • 50w条数据

  • 100w条数据

  • 500w条数据

  • 1000w条数据

这里列个表格,方便分析(时间单位ms)

数量 for循环 增强for循环 第一种写法 第二种写法
1w 7 9 90 12
10w 21 24 101 24
50w 33 41 86 25
100w 46 76 101 45
500w 159 403 207 116
1000w 299 1053 324 210
  1. 分析结果(这里使用的是ArrayList进行的测试,并没有对LinkedList进行测试,并且测试结果也可能没有那么的精确,这里采用10次求平均值的方式 )
  • 这里我们发现普通for的执行效率是比增强for效率要高的,并且随着数据量的增大,性能差距越明显
  • 随着数据量的不断增多,增强for的性能急剧下降,普通for循环的下滑并没有那么严重
  • 后面两种都是采用stream流处理的方式进行的,但是第一种写法在数据量不大的情况下,效率似乎有些太差了,不过随着数据量的增加,执行耗时并没有太大的变化,应该主要是创建流比较耗时
  • 第二种写法整体效率和普通for循环差不多,并且在数据量偏大的时候性能稍优于普通for循环

总结:普通for循环的执行效率和第二种写法的效率远高于其他两种,增强for循环性能稍弱,但效率随数据量变多效率下滑十分严重,第一种写法数据量不多时效率偏低,但是数据量较大是效率还算可以

三.分析原因

  1. 先从两种传统的for循环开始分析,因为都是二重循环,所以时间复杂度都是O(n * n),理论上时间应该差不了太多,但是我们只要看一下这两者的源码就可以知道为什么了

  • 左边的是fori循环,可以看到只进行了一个数组下标是否越界的判断就,直接返回了这个数据

  • 右边的是增强for循环,可以看到在获取数据之前进行了许多的判断,再返回数据

  1. 第一种写法的时间复杂度是O(n * n),而第二种写法的时间复杂度是O(n + n) = O(n),可以看出第二种写法的时间复杂度是最小的,但是因为是流处理,所以要创建流,这就导致在数据量小的时候流处理并不占优势,甚至效率十分的低下,但是由于第二种写法将时间复杂度降到了O(n)这才大幅度减少了其耗时

这里附上折线图,便于观察

四.总结

  1. 有些人偏爱使用stream流的形式去遍历集合(比方说我自己),但是可以看到在数据量不大的情况下,效率是偏低的,但是虽然说偏低,但也是毫秒级别的,只是相较于传统的for循环效率偏低(stream.foreach好像没有办法跳出嵌套循环,不知道有没有谁知道可以怎么做,这样可以减少不必要的循环次数)
  2. 并且在需要使用stream去进行嵌套循环的时候,推荐使用第二种写法,这种写法使用HashMap查找数据时间复杂度为O(1)的特点,降低了时间复杂度,并且不论在数据量多少的情况下,效率都十分的稳定,爱了爱了,这里我本人是比较推荐这种写法的
  3. 这里的增强for在大于100w数据的情况下性能开始极端下降,这个是需要十分注意的
  4. 传统for循环的性能也是十分稳定的,但是其使用的时候需要些很多的i,j,k类似的下标参数,这样的代码看起来会比较的混乱,代码写出来也会偏长,我不是很喜欢用,看各自喜好吧

震惊!没想到你居然是这样的for循环(UC打钱!)相关推荐

  1. 港中文大学计算机科学面试吗,听说过香港有需要面试的专业,但没想到这些居然还要笔试??...

    原标题:听说过香港有需要面试的专业,但没想到这些居然还要笔试?? Photo byRobert BakeronUnsplash 听说过香港有需要面试的专业,但没想到这些居然还要笔试?? 今天Cecil ...

  2. ps4插html屏幕不亮光,万万没想到,居然是这个!PS4黑屏的原因终于找到了!

    往往最容易获得的最容易忽视 原本想着换了新显示器就可以安逸的打机了,结果新的问题却出现了.自从PS4 Pro原装线被人"借走"后,只能用一根装机时的"赠品"顶着 ...

  3. 万万没想到,线程居然被饿死了!

    我们在构建线程池的时候可以构建单个线程的线程池和多个线程的线程池. 那么线程池使用不当可不可能产生死锁呢?我们知道死锁是循环争夺资源而产生的.线程池中的线程也是资源的一种,那么如果对线程池中的线程进行 ...

  4. char转成string_真没想到,一个小小的String居然还有这么多窍门?

    推荐学习 公司来了位阿里P8大神,看完他的手写"Kafka笔记",万分膜拜 牛掰!"基础-中级-高级"Java程序员面试集结,看完献出我的膝盖 真没想到,一个小 ...

  5. 远程抄表 本地服务器,没想到实现远程抄表真正原因居然是它

    原标题:没想到实现远程抄表真正原因居然是它 现在都是远程抄表系统,远程抄表可以杜绝人工抄表的错误和麻烦,可以让用户先付费再用电,这样管理中心资金比较容易收回,不会发生有资金断流的现象,那么远程抄表到底 ...

  6. 红米note5有没有人脸识别_红米Note5和魅蓝5对比评测 居然是它,没想到

    红米Note5和魅蓝5对比评测 居然是它,没想到 2019-03-25 09:51:13 作者:罗伯特 小米经过几年不多的积累,在粉丝中有着不错的口碑,2018年03月发布了红米Note5.魅族在近几 ...

  7. android 长时间充电,充电十分钟就能在畅玩N小时?没想到这样的手机居然真正存在!...

    充电十分钟就能在畅玩N小时?没想到这样的手机居然真正存在! 2020-05-02 10:35:49 0点赞 0收藏 0评论 玩游戏,刷抖音几乎成为了现代人每天闲暇时间必做的事情,尤其是<王者荣耀 ...

  8. 业内人士透露:百联与阿里“联姻”,三个没想到!

    2017年2月20日,有幸参加了阿里的新零售战略发布会,百联与阿里签署战略合作协议,中国最大的电商企业与最大的实体零售企业"联姻"了. 这是一件惊天大事,特别对实体零售圈. 我把消 ...

  9. 没想到我提前56年感受了赛博朋克

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI 硬核的 ...

  10. 显卡暴涨,这我万万没想到啊

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 梦晨 晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI ...

最新文章

  1. Codeforces 1300E. Water Balance[单调栈]
  2. 十一课堂|通过小游戏学习Ethereum DApps编程(3)
  3. ZServer4D开源项目
  4. envi 文件 生成mat_JVM 内存分析工具 MAT 的深度讲解与实践——入门篇
  5. 【IT资讯】继哈工大Matlab软件被美禁用后,华为、360再遭Docker软件禁令
  6. 虚拟机中dns配置好了但是域名ping不同_弱电工程中常用的几个网络命令,学会后轻松变高手...
  7. docker mysql Exit 1
  8. SpringBoot 启动报错:Failed to configure a DataSource: ‘url‘ attribute is not specified and no emb
  9. SQLServer 优化SQL语句:in 和not in的替代方案
  10. 关于unity2019.3.11.f在烘焙光照贴图时闪退的问题
  11. python输入数字是什么类型的游戏_“数字炸弹”——一个练习Python基础知识的小游戏...
  12. 吴恩达深度学习5.3练习_Sequence Models_Trigger word detection
  13. LIS (nlogn)的算法
  14. 姆巴佩独造三球一战成名 阿里云打破世界杯流量纪录
  15. Spring——Java程序员的春天
  16. 神逸之作:国产快速启动软件神品ALTRun
  17. 基于STM32的电磁寻迹智能车硬件部分总结
  18. 程序员出海创富的机会在哪里?三位专家给出具体建议
  19. JavaTutorials之Operators
  20. 电脑控制手机,无需Root、无线连接,免费开源跨平台的scrcpy比其他收费软件还好用!

热门文章

  1. A graph auto-encoder model for miRNA-disease associations prediction 论文解析
  2. el-input 只能输入整数(包括正数、负数、0)或者只能输入整数(包括正数、负数、0)和小数
  3. 和游戏服务器的连接中断错误 1,绝地求生“与Steam服务器连接时出现了一个问题”怎么解决...
  4. java生成word文件带上页码,使用apache poi api创建Word文档时,如何以Y的X格式添加页码?...
  5. 图文详解 | 万用表的使用与口诀!十足干货,不要错过!
  6. Java中易混淆问题总结
  7. R语言使用oneway.test函数执行单因素方差分析(One-Way ANOVA)、如果组间具有相同的方差则设置var.equal参数为TRUE获取更加宽松的检验
  8. stm32定时器配置与时间计算公式
  9. python中iter()的高阶用法
  10. 七天引爆社交新零售(助你提高十倍业绩)——前言