Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Java 性能优化 | 神操作:从 200 秒到 300 毫秒,性能大逆袭!

Java 性能优化 | 神操作:从 200 秒到 300 毫秒,性能大逆袭!

作者头像
架构师精进
发布于 2025-04-04 11:32:18
发布于 2025-04-04 11:32:18
16200
代码可运行
举报
文章被收录于专栏:公众号文章公众号文章
运行总次数:0
代码可运行

嘿,各位 Java 开发小伙伴们!今天给大家分享一个前几天在项目中遇到的问题,这是实际项目中非常典型的性能优化案例,相信会让你对 Java 程序性能优化有更深入的理解和启发哦。让我们一起深入探索这次从性能困境到成功优化的精彩旅程吧。

一、遇到的问题:Stream 处理的性能困境

在我们的一个实际项目中遇到了这样一个需求:计算并导出全部人员全年的 考勤情况汇总数据。

接到需求之后,感觉问题不大,就是查询出相关的数据之后,循环查找和计算的问题,我们最初采用的是一种比较常见且看起来简洁的方法:使用 Stream 和 forEach 循环处理全部的数据。具体代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
finalSummaryList.stream().parallel().forEach(summary -> {
    cycle.stream().forEach(c -> {
        // 3.2、根据 List<NewAttendanceDetailResult> list计算年事假,病假,旷工,情况,并赋值给AttendStaffLeaveSummary对象中的kuangGong1 到kuangGong12字段,病假,事假也是如此
        String key = summary.getEmCode() + "-"+ cycle;
        //计算采用的数据源
        boolean flag = calculateOldOrNewRecord(cycle,summary.getIspaiban());
        if (flag){
             NewAttendanceDetailResult record = listAtt.stream()
                .filter(r -> summary.getEmCode().equals(r.getEmCode()) && attdate.getMonth() ==r.getAttdate().getMonth())
                .findFirst().orElse(null);

            calculateLeaveFromNewAttendanceDetailResult(record,summary);
        } else {
             AttendanceRecord oldRecord = listOld.stream()
                .filter(r -> summary.getEmCode().equals(r.getEmployeenum())  && attdate.getMonth()==r.getAttdate().getMonth())
                .findFirst().orElse(null);

            calculateLeaveFromAttendanceRecord(oldRecord,summary);
        }
        System.out.println("summary complete," + summary.getEmCode());

    });
});

在上述代码中,使用了 Java 8 的流(Stream)和 Lambda 表达式,主要功能是处理 finalSummaryList 中的元素,并且使用并行流(parallel())进行处理,目的可能是为了提高处理速度。对于 finalSummaryList 中的每个元素 summary,会遍历 cycle 中的元素 c,并执行一系列操作。

二、性能表现:耗时到达200s

这种使用 Java 8 的函数式编程特性的方式,虽然简洁明了,具有很高的可读性。然而,理想很美好,现实却很残酷。当我们在处理大量数据时,这个程序的性能表现却不尽如人意。在实际运行中,我们发现整个数据导出过程异常缓慢,经过仔细的测试和计时,这个过程居然需要 180 秒以上的时间!这严重影响了我们系统的整体性能,用户在等待数据导出时可能会遭遇长时间的延迟,导致用户体验极差,甚至可能影响业务的正常开展。

三、问题分析:Stream为什么效率低

深入分析这个性能问题,我们发现其核心问题在于 Stream流处理的特性。在这个for循环中,每次迭代都会创建一个新的Stream流,并且对数据集进行filter操作。由于filter操作需要遍历所有的元素,其时间复杂度为。想象一下,当 listAtt 数据集包含大量元素,而finalSummaryList也有众多元素时,我们就会陷入一个恶性循环:在每次for循环迭代中,都需要对listAtt 进行多次遍历和筛选操作,这就像在一个庞大的图书馆里,每次找一本书都要重新把书架上的书一本本检查一遍,效率自然低下。这种重复的高时间复杂度操作,随着数据量的增加,性能开销会呈指数级增长,最终导致程序像蜗牛一样慢,极大地影响了系统的响应速度和用户体验。

四、优化解决:转向 Map 查找的方案

为了克服这个性能瓶颈,我们开始了一系列的优化探索。经过多次尝试和测试,最终发现将 listAtt 转换为 Map 并使用 get(key) 进行查找的方式效果非常显著。

我们首先使用 stream().collect(Collectors.toMap(...))方法将数据集转换为Map。这里,我们将NewAttendanceDetailResultemCode和attDate作为键,将NewAttendanceDetailResult对象本身作为值存储在Map中。这个转换过程会遍历listAtt一次,将元素存储到Map 中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Map<String,NewAttendanceDetailResult> listNewResult =listAtt.stream()
// 提取每个对象的键(由emCode和attdate的年月组成)以及对应的对象本身
.collect(Collectors.toMap(
        att -> {
            String emCode = att.getEmCode();
            Date attdate =  att.getAttdate();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            String attdateStr = sdf.format(attdate);
            return emCode + "-" + attdateStr;
        },
        att -> att
));

然后,在 for 循环中,我们通过 get(key) 方法直接从 Map 中查找元素。当我们完成这次优化并运行程序时,效果立竿见影,数据处理时间从之前的 200 秒以上迅速缩减到了仅仅 1 到 2 秒!这个结果让我们团队感到非常兴奋。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
finalSummaryList.stream().parallel().forEach(summary -> {
    cycle.stream().forEach(c -> {
        // 3.2、根据 List<NewAttendanceDetailResult> list计算年事假,病假,旷工,情况,并赋值给AttendStaffLeaveSummary对象中的kuangGong1 到kuangGong12字段,病假,事假也是如此
        String key = summary.getEmCode() + "-"+ cycle;
        //计采用的数据源
        boolean flag = CalOldOrNewRecord(cycle,summary.getIspaiban());
        if (flag){
            NewAttendanceDetailResult record = listNewResult.get(key);
            calculateLeaveFromNewAttendanceDetailResult(record,summary);
        } else {
            AttendanceRecord oldRecord= list.get(key);
            calculateLeaveFromAttendanceRecord(oldRecord,summary);
        }
        System.out.println("summary complete," + summary.getEmCode());
    });
});

优化后的结果:

五、优化原理:深入剖析性能提升的秘密

那么,为什么会有如此显著的性能提升呢 让我们来深入剖析一下其中的原理吧。

Stream 处理的性能分析

在使用Stream处理时,每次for循环迭代都会创建一个新的Stream实例,并且在filter操作中,它需要遍历List中的元素。这个filter操作实际上是在执行一个条件判断来筛选元素,对于List中的每个元素都要进行这样的判断,这意味着时间复杂度是一个

的操作。而且,由于for循环的存在,对于List中的每个元素,都会触发这样一个的查找过程,这是一个嵌套的时间复杂度问题,整体性能会变得非常糟糕,特别是当数据量较大时,计算量会成倍增加。

Map 查找的性能优势

六、总结与启示:性能优化的思考与实践经验

通过这次性能优化的实践,我们获得了很多宝贵的经验。

  • 在处理小数据集时,使用 Stream 流处理可以使代码更加简洁和具有可读性,并且由于数据量小,性能损失并不明显,是一个不错的选择。它能够让我们以一种函数式的编程风格来表达复杂的数据处理逻辑,提高代码的可维护性和开发效率。
  • 然而,当面对大数据集,尤其是在 for 循环中需要频繁查找元素时,将列表转换为 Map 进行查找是一种更优的策略。这种方式利用了 Map 的高效查找特性,能够极大地减少查找元素的时间,显著提升程序性能,让程序运行得更加流畅,避免了因性能问题导致的长时间等待和用户体验下降。

启示

  • 在开发过程中,我们不能仅仅满足于代码的简洁性和功能性,还需要考虑性能因素。对于不同的数据处理场景,要根据数据量和操作频率等因素,灵活选择合适的数据结构和算法。
  • 性能优化往往需要我们深入理解数据结构和操作的时间复杂度,分析代码的执行过程,找到性能瓶颈所在,而不是仅仅依赖于表面上的代码简洁性。有时候,看似简单的代码可能隐藏着性能陷阱,而一些看起来稍微复杂一点的优化方案,可能会带来意想不到的性能提升。

希望大家从这个案例中获得启发,在自己的开发工作中更加注重性能优化。在面对性能问题时,不要害怕尝试不同的方法,深入分析和理解底层原理,找到最适合自己项目的解决方案。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构师精进 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java流的性能优化:提升数据处理速度的策略!
咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE相关知识点了,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~
bug菌
2024/09/20
1690
Java流的性能优化:提升数据处理速度的策略!
Java8中的流操作-基本使用&性能测试
流是 Java8 中 API 的新成员,它允许你以声明式的方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。这有点儿像是我们操作数据库一样,例如我想要查询出热量较低的菜品名字我就可以像下面这样:
我没有三颗心脏
2019/08/06
1K0
Java8中的流操作-基本使用&性能测试
10种简单的Java性能优化学习
10种简单的Java性能优化学习 你是否正打算优化hashCode()方法?是否想要绕开正则表达式?Lukas Eder介绍了很多简单方便的性能优化小贴士以及扩展程序性能的技巧。 最近“全网域(Web Scale)”一词被炒得火热,人们也正在通过扩展他们的应用程序架构来使他们的系统变得更加“全网域”。但是究竟什么是全网域?或者说如何确保全网域? 扩展的不同方面 全网域被炒作的最多的是扩展负载(Scaling load),比如支持单个用户访问的系统也可以支持10 个、100个、甚至100万个用户访问。在理想情
用户1289394
2018/02/26
1.3K0
10种简单的Java性能优化学习
Stream API数据流操作:什么是Stream API?如何在JDK 8中实现链式数据处理?
JDK 8引入了Stream API,极大地简化了对集合数据的处理。通过Stream API,你可以实现链式数据操作,包括过滤、映射、聚合等功能,使代码更加简洁优雅。在本篇文章中,猫头虎将详细解析:
猫头虎
2024/12/18
1770
Stream API数据流操作:什么是Stream API?如何在JDK 8中实现链式数据处理?
Java遍历集合的几种方法分析(实现原理、算法性能、适用场合)
Java语言中,提供了一套数据集合框架,其中定义了一些诸如List、Set等抽象数据类型,每个抽象数据类型的各个具体实现,底层又采用了不同的实现方式,比如ArrayList和LinkedList。
Java团长
2018/08/07
1.1K0
Java 中 10 大简单的性能优化
Java 7 ForkJoinPool和 Java 8 的并行Stream有助于并行化东西,这在您将 Java 程序部署到多核处理器机器上时非常有用。与跨网络上的不同机器进行扩展相比,这种并行性的优势在于您几乎可以完全消除延迟效应,因为所有内核都可以访问相同的内存。但是不要被并行的效果所迷惑!记住以下两点:
终码一生
2022/04/15
3750
Java 中 10 大简单的性能优化
Python代码性能优化归纳总结,干货收藏
Python 是一种脚本语言,相比 C/C++ 这样的编译语言,在效率和性能方面存在一些不足。但是,有很多时候,Python 的效率并没有想象中的那么夸张。本文对一些 Python 代码加速运行的技巧进行整理。
用户6888863
2022/04/13
9790
Python性能优化全攻略:10个实用技巧大公开
Python,作为一种动态类型的解释性语言,确实在执行速度上可能不如C这样的静态类型的编译语言。但是,通过一些技巧和策略,我们可以显著提升Python代码的性能。
小羽网安
2024/06/21
3160
Python性能优化全攻略:10个实用技巧大公开
Java Stream 奇淫技巧
在现代编程的世界里,Java Stream 就像是编程语言的江湖。正如武侠小说中的高手一样,只有掌握了Stream的奇淫技巧,才能在代码的江湖中纵横驰骋。今天,就让我们放下剑与魔法,拿起键盘和代码,一起踏上Java Stream的修炼之路。
繁依Fanyi
2024/08/08
1630
【文章笔记】性能优化技巧参考
原文如下:https://mp.weixin.qq.com/s/yXVkHSRdwjXFM7Xv03x3-Q
阿东
2022/12/21
4830
【文章笔记】性能优化技巧参考
全面吃透JAVA Stream流操作,让代码更加的优雅
在JAVA中,涉及到对数组、Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行处理。
是Vzn呀
2022/07/14
3.3K0
全面吃透JAVA Stream流操作,让代码更加的优雅
Java8中的Stream API详解
在传统的J2EE应用中,Java代码经常不得不依赖于关系型数据库的聚合操作来完成诸如:
用户4396583
2024/08/03
1430
Java性能优化技巧:如何避免常见的陷阱
在本文中,我将带你了解一些Java性能优化技巧。通过专门研究Java程序中的某些操作。这些技巧仅真正适用于特定的高性能方案,因此,由于速度差异很小,因此无需使用这种方法编写所有代码。但是,在热代码路径中,它们可能会产生很大的不同。
陈哈哈
2020/07/06
5920
Java性能优化技巧:如何避免常见的陷阱
5秒到1秒,记一次效果“非常”显著的性能优化
性能优化,有时候看起来是一个比较虚的技术需求。除非代码慢的已经让人无法忍受,否则,很少有公司会有觉悟投入资源去做这些工作。即使你有了性能指标数据,也很难说服领导做一个由耗时300ms降低到150ms的改进,因为它没有业务价值。
xjjdog
2021/09/17
6620
【前端】JavaScript 中数组的基本操作及优化题解
首先来看一道基础的题目,题目要求我们对数组中的所有数进行求和,然后计算出数组的平均值。以下是原题目以及初始解法:
CSDN-Z
2024/11/21
1220
【前端】JavaScript 中数组的基本操作及优化题解
Python 性能优化的20条招数
优化算法时间复杂度 算法的时间复杂度对程序的执行效率影响最大,在 Python 中可以通过选择合适的数据结构来优化时间复杂度,如 list 和 set 查找某一个元素的时间复杂度分别是O(n)和O(1
小小科
2018/05/04
1.2K0
Python 性能优化的20条招数
Java基础篇 | Java流式编程
Java 流(Stream)是一连串的元素序列,可以进行各种操作以实现数据的转换和处理。流式编程的概念基于函数式编程的思想,旨在简化代码,提高可读性和可维护性。
程序员Leo
2023/11/16
1.3K0
Java基础篇 | Java流式编程
【深入浅出C#】章节10: 最佳实践和性能优化:性能调优和优化技巧
理解性能优化的重要性: 性能优化是软件开发中至关重要的一部分,因为它直接关系到用户体验、资源利用率和系统可伸缩性。以下是性能优化的一些重要原因:
喵叔
2023/09/25
2.3K0
Java8新特性:stream流应用,丢掉for循环实现复杂遍历功能
stream流是支持数据处理操作的数据源生成的元素序列,这些数据源可以是集合、数组、文件I/O channel等。stream不是一种数据结构,也不会存储数据,并且它支持数据聚合操作,如过滤filter、映射map、去重distinct、匹配match等等。
鳄鱼儿
2024/05/21
6200
Python代码性能优化
在python2中,range的实现方式是直接在内存中开辟一个静态的数组,而xrange则是通过迭代的方式动态的去生成,所以显而易见,在需要的数据量特别大的时候,range则会非常的耗费内存,所以其优化方式如下:
py3study
2020/01/06
4570
推荐阅读
相关推荐
Java流的性能优化:提升数据处理速度的策略!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验