news 2026/4/18 5:22:43

公司来了个新同事,把代码耗时从 26856ms 优化到了 748ms,一顿操作猛如虎!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
公司来了个新同事,把代码耗时从 26856ms 优化到了 748ms,一顿操作猛如虎!

在两张表中查找相同 ID 的数据时,许多开发者会使用两层for循环嵌套。这种写法效率较低,本文将介绍一种提高查找速度的优化方法。

场景

for循环内嵌套for循环,进行数据匹配和处理。时间复杂度为 O(n*m),在数据量较大时性能会急剧下降。

示例

假设有两份List数据:userListuserMemoList。需要遍历userList,根据每个用户的userId,从userMemoList中查找并取出对应userIdcontent值进行后续处理。

import lombok.Data; import java.util.*; import java.util.stream.Collectors; import org.springframework.util.StringUtils; @Data class User { private Long userId; private String name; } @Data class UserMemo { private Long userId; private String content; } public class NestedLoopOptimization { 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; } // ... 后续代码 }

模拟数据:5 万条user数据,3 万条userMemo数据。

未优化的代码

最直接的实现方式,通过两层for循环进行匹配:

public static void nestedLoop(List<User> userTestList, List<UserMemo> userMemoTestList) { 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); // 避免打印影响测试结果 } } } }

耗时:约数万毫秒 (5 万 * 3 万次迭代)。

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

break 优化

当每个userIduserMemoList中只有一条数据时,找到匹配项后直接break跳出内循环:

public static void breakOptimizedLoop(List<User> userTestList, List<UserMemo> userMemoTestList) { 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; // 找到匹配项后跳出内循环 } } } }

耗时:仍然需要遍历较多次,但比嵌套循环略有改善。

使用 Map 优化

public static void mapOptimizedLoop(List<User> userTestList, List<UserMemo> userMemoTestList) { 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); // 避免打印影响测试结果 } } }

耗时:显著减少,通常在数百毫秒级别。

原理

两层for循环嵌套的时间复杂度为 O(n*m),其中 n 和 m 分别为两个列表的长度。使用Map后,get操作的时间复杂度接近 O(1),整体时间复杂度降为 O(n+m),避免了内循环的重复遍历。

HashMapget方法内部使用了getNode方法来查找键值对。getNode方法利用哈希表结构,快速定位到目标键值对。虽然在极端情况下(所有键的哈希值都相同),getNode的时间复杂度会退化为 O(n),但在实际应用中,哈希冲突的概率很低,HashMapget操作效率通常很高。因此无需过于担心O(n)的最坏情况.

// HashMap.getNode() 方法的部分关键代码 (JDK8) final Node<K,V> getNode(int hash, Object key) { // ... (省略部分代码) if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k)))) return first; // 找到节点,直接返回 // ... (省略处理哈希冲突的代码) }

通过以上优化,可以显著提高代码的执行效率。尤其是在处理大量数据时,使用Map优化能够带来巨大的性能提升。避免了不必要的计算,从而提升了代码的性能。

总结

优化方法时间复杂度适用场景性能提升
未优化(嵌套循环)O(n * m)数据量较小时可接受最低,耗时数万毫秒
break优化O(n * m)数据量较小,且userId唯一时适用略有提升,减少内循环次数
Map优化O(n + m)数据量大,且需要高效匹配时适用显著提升,耗时百毫秒级
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 9:21:32

IMFBS01现场接口模块

IMFBS01 现场接口模块是工业自动化系统中的信号转换与传递单元&#xff0c;主要用于连接控制系统与现场设备&#xff0c;实现各种输入输出信号的可靠接入与分发。主要功能说明&#xff1a;提供多通道输入/输出接口&#xff0c;用于采集或输出现场信号。支持数字量和模拟量信号的…

作者头像 李华
网站建设 2026/4/10 18:07:16

本站最全网络安全学习路线图(2026版详解版)

近期&#xff0c;大家在网上对于网络安全讨论比较多&#xff0c;想要学习的人也不少&#xff0c;但是需要学习哪些内容&#xff0c;按照什么顺序去学习呢&#xff1f;其实我们已经出国多版本的网络安全学习路线图&#xff0c;一直以来效果也比较不错&#xff0c;本次我们针对市…

作者头像 李华
网站建设 2026/4/17 18:52:37

Github Copilot使用指南

tab 自动补齐代码或者注释ctrl i 内联聊天根据你的要求生成代码agent能够使用执行命令行命令&#xff0c;但是Edit不能

作者头像 李华
网站建设 2026/4/16 8:10:26

MindSpore 大模型训练进阶:高效显存管理 + 增量式断点续训的实践

在千亿参数大模型&#xff08;如 LLaMA-7B/13B&#xff09;的训练场景中&#xff0c;显存瓶颈与训练中断恢复是两大核心痛点 —— 前者直接限制模型规模&#xff0c;后者会导致工业级训练的时间与算力成本翻倍。本次分享基于 MindSpore 的高阶训练特性&#xff0c;构建 “分层显…

作者头像 李华
网站建设 2026/3/28 9:06:35

Spring Boot 3 集成 Apache Calcite:多数据源查询的终极解决方案

熟悉 Spring Boot 3 的开发者&#xff0c;都知道它在简化开发流程、提高开发效率方面的出色表现吧&#xff01;但是&#xff0c;在实际业务场景中&#xff0c;大家肯定都碰到过这样的棘手问题&#xff1a;订单数据存放在 MySQL 里&#xff0c;库存数据在 PostgreSQL 中&#xf…

作者头像 李华