Java for循环嵌套for循环,你需要懂的代码性能优化技巧

article/2025/9/24 3:32:24

前言

本篇分析的技巧点其实是比较常见的,但是最近的几次的代码评审还是发现有不少兄弟没注意到。

所以还是想拿出来说下。
 

正文

是个什么场景呢? 

就是 for循环 里面还有 for循环, 然后做一些数据匹配、处理 这种场景。

我们结合实例代码来看看。

场景示例:

比如我们现在拿到两个list 数据 ,

一个是 User List 集合 ;

另一个是 UserMemo List集合;


我们需要遍历 User List ,然后根据 userId 从 UserMemo List 里面取出 对应这个userId 的 content 值,做数据处理。

代码  User.java :

import lombok.Data;@Data
public class User {private Long userId;private String name;
}

代码 UserMemo.java :

import lombok.Data;@Data
public class UserMemo {private Long userId;private String content;
}

模拟 数据集合 :

5W 条 user 数据 , 3W条 userMemo数据 

    public static List<User> getUserTestList() {List<User> users = new ArrayList<>();for (int i = 1; i <= 50000; i++) {User user = new User();user.setName(UUID.randomUUID().toString());user.setUserId((long) i);users.add(user);}return users;}public static List<UserMemo> getUserMemoTestList() {List<UserMemo> userMemos = new ArrayList<>();for (int i = 30000; i >= 1; i--) {UserMemo userMemo = new UserMemo();userMemo.setContent(UUID.randomUUID().toString());userMemo.setUserId((long) i);userMemos.add(userMemo);}return userMemos;}

先看平时大家不注意的时候可能会这样去写代码处理 :

 ps: 其实数据量小的话,其实没多大性能差别,不过我们还是需要知道一些技巧点。

代码:

    public static void main(String[] args) {List<User> userTestList = getUserTestList();List<UserMemo> userMemoTestList = getUserMemoTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();for (User user : userTestList) {Long userId = user.getUserId();for (UserMemo userMemo : userMemoTestList) {if (userId.equals(userMemo.getUserId())) {String content = userMemo.getContent();System.out.println("模拟数据content 业务处理......"+content);}}}stopWatch.stop();System.out.println("最终耗时"+stopWatch.getTotalTimeMillis());}

我们来看看 这时候的一个耗时情况 :

相当于迭代了 5W * 3W 次 

可以看到用时 是 26857毫秒 

其实到这,插入个题外点,如果说每个userId 在 UserMemo List 里面 都是只有一条数据的场景。

        for (User user : userTestList) {Long userId = user.getUserId();for (UserMemo userMemo : userMemoTestList) {if (userId.equals(userMemo.getUserId())) {String content = userMemo.getContent();System.out.println("模拟数据content 业务处理......"+content);}}}

单从这段代码有没有问题 ,有没有优化点。

显然是有的, 因为当我们从内循环UserMemo List里面找到匹配数据的时候, 没有做其他操作了。

这样 内for循环会继续下,直到跑完再进行下一轮整体循环。

所以,仅针对这种情形,1对1的或者说我们只需要找到一个匹配项,处理完后我们 应该使用 break


我们来看看 加上 break 的一个耗时情况 :

 代码:

    public static void main(String[] args) {List<User> userTestList = getUserTestList();List<UserMemo> userMemoTestList = getUserMemoTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();for (User user : userTestList) {Long userId = user.getUserId();for (UserMemo userMemo : userMemoTestList) {if (userId.equals(userMemo.getUserId())) {String content = userMemo.getContent();System.out.println("模拟数据content 业务处理......"+content);break;}}}stopWatch.stop();System.out.println("最终耗时"+stopWatch.getTotalTimeMillis());}

耗时情况:
 

可以看到 从 2W 多毫秒 变成了 1W 多毫秒, 这个break 加的很OK。


回到我们刚才, 平时需要for 循环 里面再 for 循环 这种方式,可以看到耗时是 2万6千多毫秒。

那如果场景更复杂一定, 是for 循环里面 for循环 多个或者, for循环里面还有一层for 循环 ,那这样代码耗时真的非常恐怖。


那么接下来这个技巧点是 使用map 去优化 :

代码:
 

    public static void main(String[] args) {List<User> userTestList = getUserTestList();List<UserMemo> userMemoTestList = getUserMemoTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();//使用stream() 记得一定要判空 这里没列出来,大家自己注意Map<Long, String> contentMap =userMemoTestList.stream().collect(Collectors.toMap(UserMemo::getUserId, UserMemo::getContent));for (User user : userTestList) {Long userId = user.getUserId();String content = contentMap.get(userId);if (StringUtils.hasLength(content)) {System.out.println("模拟数据content 业务处理......" + content);}}stopWatch.stop();System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());}

看看耗时:

为什么 这么显著的效果 ?


这其实就是时间复杂度,

for循环嵌套for循环,


就好比 循环每一个 user ,拿出 userId 

需要在里面的循环从 userMemo list集合里面 按顺序去开盲盒匹配,


拿出第一个,看看userId ,拿出第二个,看看userId ,一直找匹配的。

而我们提前对 userMemo list集合 做一次 遍历,转存储在map里面 。


map的取值效率 在多数的情况下是能维持接近 O(1) 的 , 毕竟数据结构摆着,数组加链表。


相当于拿到userId  想去开盲盒的时候, 根据userId 这个key  hash完能直接找到数组里面的索引标记位, 如果底下没链表(有的话O(logN)),直接取出来就完事了。

然后补充一个getNode的代码注释 : 

/*** Implements Map.get and related methods.* 这是个 Map.get 的实现 方法* @param hash hash for key* @param key the key* @return the node, or null if none*/
//    final 写死了 无法更改 返回 Node 传入查找的 hash 值 和 key键final Node<K,V> getNode(int hash, Object key) {
//        tab 还是 哈希表
//        first 哈希表找的链表红黑树对应的 头结点
//        e 代表当前节点
//        k 代表当前的 keyNode<K,V>[] tab; Node<K,V> first, e; int n; K k;
//        赋值 并过滤 哈希表 空的长度不够的 对应位置没存数据的 都直接 return nullif ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {
//            头结点就 找到了 hash相等值相等 或者 不空的 key 和当前节点 equalsif (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;
//            头结点不匹配 没找到就 就用 next 找if ((e = first.next) != null) {
//                是不是红黑树 的if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);
//                红黑树就直接 调用 红黑树内查找//                不为空或者没找到就do while 循环do {
//                    当前节点 找到了 hash相等值相等 或者 不空的 key 和当前节点 equalsif (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}
=

按照目前以JDK8 的hash算法,起hash冲突的情况是非常非常少见了。
最恶劣的情况,只有当 全部key 都冲突, 全都分配到一个桶里面去都占用一个位置 ,这时候就是O(n),这种情景不需要去考虑。

好了,该篇就到这。


http://chatgpt.dhexx.cn/article/ExcIyqCd.shtml

相关文章

Java for循环嵌套

一、需求 需求1&#xff1a;打印以下图形 **** **** **** for(int i 0;i<3;i){//控制行数for(int j 0;j<4;j){//控制列数System.out.print("*");}System.out.println(); } 需求2&#xff1a;打印以下图形 …

C语言for循环语句及嵌套(误区,易错点要理解)

目录 前言 例题1&#xff1a; 例题2&#xff1a; for循环中contiune的使用&#xff1a; 前言 大家好&#xff0c;相信刚学C语言的小白们&#xff0c;觉得for循环是比较好用的&#xff0c;但是有时候写for循环语句的程序时&#xff0c;写出来的代码结果&#xff0c;和自己想要…

for循环嵌套

文章目录 一、什么是循环嵌套&#xff1f;二、实例1.输出一个矩阵2.输出九九乘法表 一、什么是循环嵌套&#xff1f; 外层循环和内层循环交叉执行&#xff0c;外层 for 每执行一次&#xff0c;内层 for 就要执行符合循环条件的次数。 二、实例 1.输出一个矩阵 代码如下&…

44. python的for循环嵌套

44. python的for循环嵌套 文章目录 44. python的for循环嵌套1. 什么是嵌套2. for循环中嵌套有if条件判断语句2.1 先创建一个奇数序列2.2 判断一个数是否能被7整除2.3 将2部分代码合二为一 3. for循环中嵌套有for循环 1. 什么是嵌套 嵌套是指一个对象中包含另一个与它相似的对象…

【C语言初学必看】一知半解的for循环嵌套for循环

&#x1f525;&#x1f680;前言目录&#xff1a; 初学C语言&#xff0c;常常遇到for循环中嵌套个for循环&#xff0c;初学者对于这种形式总是一知半解&#xff0c;这次我就整理了常见的for循环嵌套for循环的题目&#xff0c;我们一起争取一举拿下这类题。学废他们&#xff0c;…

双重for循环(嵌套for循环)

什么是双重循环&#xff1f; 双重循环&#xff1a;我们从字面上理解它&#xff0c;就是有两个循环套在一起 详细解释 双重for循环就是在一个for循环里在嵌套另一个for循环&#xff0c;即两个循环嵌套&#xff0c;还有多重循环嵌套的情况&#xff0c;但用的比较少&#xff0c…

DRN ---Closed-loop Matters: Dual Regression Networks for Single Image Super-Resolution

Closed-loop Matters: Dual Regression Networks for Single Image Super-Resolution 这篇博客主要介绍一下DRN&#xff0c;这是2020年最新出来超分辨重建文章。相信大家都阅读过很多超分辨率的文章&#xff0c;都知道超分辨率是一病态的问题。因为在现实生活中一张低分辨率图…

深度学习——Dual Regression Networks for Single Image Super-Resolution(DRN)

CVPR2020原论文&#xff1a;Closed-loop Matters: Dual Regression Networks forSingle Image Super-Resolution 开源代码&#xff08;pytorch框架&#xff09;&#xff1a;https://github.com/guoyongcs/DRN 1.问题 1&#xff09;低分辨率图像&#xff08;Low Resulotion&…

DRN(CVPR2020)Dual Regression Networks

DRN: [ Closed-loop Matters: Dual Regression Networks for Single Image Super-Resolution ]DRN文论链接 SISR两个潜在的局限 学习LR到HR的隐射是一个病态问题&#xff0c;因为从HR下采样到LR&#xff0c;可以有无限个HR与LR对应。所以解空间太大&#xff0c;很难找到很好的…

DRN:Dilated Residual Networks(论文解读十四)

Title&#xff1a;Dilated Residual Networks From&#xff1a;CVPR2017 Note data&#xff1a;2019/06/12 Abstract&#xff1a;提出一种有利于分类任务的扩张残差网络DRN。 Code &#xff1a;pytorch 目录 DRN论文解读 1 Abstra 2 Introduction 3 Method Degridding …

浅谈深度神经网络 — ResNet(DRN)

Deep Residual Learning for Image Recognition 1. 思想 作者根据输入将层表示为学习残差函数。实验表明&#xff0c;残差网络更容易优化&#xff0c;并且能够通过增加相当的深度来提高准确率。 核心是解决了增加深度带来的副作用&#xff08;退化问题&#xff09;&#xff0…

深度学习——BRNN和DRNN

双向循环神经网络&#xff08;Bidirectional RNN&#xff09; 双向 RNN 模型可以让你在序列的某点处不仅可以获取之前的信息&#xff0c;还可以获取未来的信息 why we need BRNN&#xff1f; 这个网络有一个问题&#xff0c;在判断第三个词 Teddy&#xff08;上图编号 1 所示&a…

DPRNN的学习

可以以非常简单的方式组织任意类型的RNN层&#xff08;不重要&#xff0c;因为我这里会换成transformer&#xff09;。 优点&#xff1a; 1.模型更小 2.性能更好&#xff08;SI-SNR&#xff09; 模型组成&#xff1a; 首先肯定是encoder和decoder了&#xff0c;一个声音的…

drndrn_seg代码

问题&#xff1a; drn文件 import pdb #pdb是 ThePythonDebugger 的缩写&#xff0c;为Python标准库的一个模块。pdb模块规定了一个Python程序交互式源代码调试器&#xff0c;支持在设置断点&#xff08;包括条件断点&#xff09;&#xff0c;也支持源码级单步调试&#xff…

深度学习——DRD-Net

CVPR2020原论文&#xff1a;Detail-recovery Image Deraining via Context Aggregation Networks 开源代码&#xff08; tensorflow框架&#xff09;&#xff1a;https://github.com/Dengsgithub/DRD-Net 1.主要工作&#xff1a;提出了双分支去雨网络。一个分支为基于压缩激励…

论文阅读:DRN: A Deep Reinforcement Learning Framework for News Recommendation

文章目录 摘要一、Introduction1、引入原因2、结构框架 二、相关工作1、新闻推荐算法2、推荐中的强化学习3、问题定义 三、实现原理1、模型框架2、特征构造3、深度强化推荐Deep Reinforcement Recommendation4、用户活跃度5、探索 四、实验结果1、数据集2、评价指标3、实验设置…

使用飞桨PaddlePaddle复现用于图像光源处理的深度重照明网络(DRN)

使用飞桨PaddlePaddle复现用于图像光源处理的深度重照明网络&#xff08;DRN&#xff09; 一、效果展示二、实现思路冠军模型&#xff1a;Wavelet Decomposed RelightNet (WDRN)经典模型&#xff1a;Norm-Relighting-U-Net (NRUNet)本次项目&#xff1a;Deep Relighting Networ…

弱监督学习框架 Detectron2/DRN-WSOD-pytorch 在服务器/windows上配置安装及使用

最近做弱监督学习研究&#xff0c;进行相关分析。发现Detectron2是一个不错的框架&#xff0c;其中也有model zoo相当多种类的预训练模型可以拿来直接用。但是安装配置使用中碰到了许多坑。跟各位小伙伴们分享。 推荐使用Linux Ubuntu16.04以上版本安装&#xff0c;虚拟机不太…

大话深度残差网络(DRN)ResNet网络原理

—— 原文发布于本人的微信公众号“大数据与人工智能Lab”&#xff08;BigdataAILab&#xff09;&#xff0c;欢迎关注。 一说起“深度学习”&#xff0c;自然就联想到它非常显著的特点“深、深、深”&#xff08;重要的事说三遍&#xff09;&#xff0c;通过很深层次的网络实现…

DRN: A Deep Reinforcement Learning Framework for News Recommendation学习

欢迎转载&#xff0c;请注明出处https://blog.csdn.net/ZJKL_Silence/article/details/85798935。 本文提出了&#xff08;基于深度Q-learning 的推荐框架&#xff09;基于强化学习的推荐系统框架来解决三个问题&#xff1a; 1&#xff09;首先&#xff0c;使用DQN网络来有效建…