当前位置: 首页 > article >正文

【020】Optional、Stream、Lambda:风格与性能注意点

写业务代码时你可能已经用上了 Lambda 和 Streamlist.stream().filter(User::isActive).map(User::getName).collect(Collectors.toList());但有没有想过Optional 什么时候该用、什么时候不该用Stream 真的比 for 循环快吗Lambda 有什么性能问题函数式编程能让代码更简洁但用错了反而带来问题。这篇帮你把 Optional、Stream、Lambda 彻底搞明白在业务代码中用对地方。1. Optional空指针的终结者1.1 Optional 是什么Optional是 Java 8 引入的容器类用来包装可能为 null 的值避免空指针。// 之前UseruseruserService.findById(1L);if(user!null){System.out.println(user.getName());}// 之后OptionalUseroptionalOptional.ofNullable(userService.findById(1L));optional.ifPresent(u-System.out.println(u.getName()));1.2 Optional 的创建// 创建 OptionalOptionalStringemptyOptional.empty();// 空 OptionalOptionalStringofOptional.of(hello);// 非空值不能为 nullOptionalStringofNullableOptional.ofNullable(null);// 可以为 null1.3 Optional 的使用场景1.3.1 方法返回值// 之前返回 nullpublicUserfindById(Longid){returnuserMapper.selectById(id);// 可能为 null}// 之后返回 OptionalpublicOptionalUserfindById(Longid){returnOptional.ofNullable(userMapper.selectById(id));}1.3.2 链式调用避免 NPE// 之前层层判空UserusergetUser();if(user!null){Addressaddressuser.getAddress();if(address!null){Stringcityaddress.getCity();// 处理 city}}// 之后链式调用StringcityOptional.ofNullable(getUser()).map(User::getAddress).map(Address::getCity).orElse(未知);1.3.3 集合操作// 之前ListStringlistgetList();if(list!null!list.isEmpty()){// 处理}// 之后Optional.ofNullable(getList()).filter(list-!list.isEmpty()).ifPresent(list-// 处理);1.4 Optional 的常见错误1.4.1 不要用 Optional 作为字段// ❌ 错误Optional 作为字段publicclassUser{privateOptionalStringname;// 不推荐}// ✅ 正确普通字段publicclassUser{privateStringname;// 可以为 null}原因Optional 不能序列化会带来额外开销。1.4.2 不要用 Optional 作为方法参数// ❌ 错误Optional 作为参数publicvoidmethod(OptionalStringparam){}// ✅ 正确普通参数publicvoidmethod(Stringparam){}1.4.3 避免过度使用// ❌ 过度使用Optional.ofNullable(user).map(u-u.getName()).map(name-name.toUpperCase()).orElse();// ✅ 简单场景不用 OptionalStringnameuser!null?user.getName():;1.5 Optional 常用方法方法作用ofNullable()创建 Optional可 nullof()创建 Optional非 nullnull 会抛异常isPresent()判断是否有值ifPresent()有值时执行操作orElse()有值返回值无值返回默认值orElseGet()有值返回值无值计算默认值orElseThrow()有值返回值无值抛异常map()转换值flatMap()转换并展平 Optionalfilter()过滤2. Stream函数式数据处理 2.1 Stream 是什么Stream 是 Java 8 引入的函数式数据处理 API支持链式操作ListIntegernumbersArrays.asList(1,2,3,4,5);// 传统写法ListIntegerresultnewArrayList();for(Integern:numbers){if(n%20){result.add(n*2);}}// Stream 写法ListIntegerresultnumbers.stream().filter(n-n%20)// 过滤偶数.map(n-n*2)// 翻倍.collect(Collectors.toList());2.2 Stream 的组成Stream 操作 │ ├─ 创建Source │ ├─ stream() │ ├─ of() │ └─ generate() │ ├─ 中间操作Intermediate │ ├─ filter()过滤 │ ├─ map()转换 │ ├─ flatMap()扁平化 │ ├─ distinct()去重 │ ├─ sorted()排序 │ └─ limit() / skip()限制 │ └─ 终端操作Terminal ├─ collect()收集 ├─ forEach()遍历 ├─ toArray()转数组 ├─ reduce()聚合 └─ min() / max() / count()2.3 惰性求值Stream 的中间操作是惰性的只有遇到终端操作才会执行// 这段代码不会执行任何操作stream().filter(n-{System.out.println(filter: n);returnn0;}).map(n-{System.out.println(map: n);returnn*2;});// 只有遇到终端操作才会执行ListIntegerresultstream().filter(n-n0).map(n-n*2).collect(Collectors.toList());2.4 短路操作短路操作可以在遇到满足条件的元素时提前结束// findAny找到第一个就返回OptionalIntegerfirstlist.stream().filter(n-n5).findAny();// anyMatch任意一个匹配就返回 truebooleanhaslist.stream().anyMatch(n-n10);// allMatch全部匹配才返回 truebooleanalllist.stream().allMatch(n-n0);// noneMatch全部不匹配才返回 truebooleannonelist.stream().noneMatch(n-n0);// limit限制数量list.stream().limit(10)// 只取前 10 个.collect(Collectors.toList());2.5 并行 Stream// 顺序 Streamlist.stream().map(String::toUpperCase).collect(Collectors.toList());// 并行 Stream多线程处理list.parallelStream().map(String::toUpperCase).collect(Collectors.toList());注意并行 Stream 不是万能的小数据量可能更慢。3. Lambda 表达式 3.1 Lambda 是什么Lambda 是匿名函数用来简化代码// 之前匿名内部类RunnablernewRunnable(){Overridepublicvoidrun(){System.out.println(Hello);}};// 之后LambdaRunnabler()-System.out.println(Hello);3.2 Lambda 语法// 无参数()-System.out.println(Hello)// 单参数括号可省略x-x*2// 等价于(x)-x*2// 多参数(x,y)-xy// 多行语句(x,y)-{intsumxy;returnsum;}3.3 数式接口Lambda 只能用于函数式接口只有一个抽象方法的接口FunctionalInterfaceinterfaceCalculator{intcalculate(inta,intb);}// 使用Calculatoradd(a,b)-ab;Calculatormultiply(a,b)-a*b;常见的函数式接口接口方法用途Runnablevoid run()无参数无返回值SupplierTT get()无参数有返回值ConsumerTvoid accept(T t)有参数无返回值FunctionT,RR apply(T t)有参数有返回值PredicateTboolean test(T t)布尔判断BiFunctionT,U,RR apply(T t, U u)两参数有返回值3.4 方法引用方法引用是 Lambda 的简写形式// Lambdalist.stream().map(s-s.toUpperCase()).collect(Collectors.toList());// 方法引用list.stream().map(String::toUpperCase).collect(Collectors.toList());方法引用的四种形式// 1. 静态方法引用ClassName::staticMethodFunctionString,IntegerparserInteger::parseInt;// 2. 实例方法引用instance::instanceMethodStringstrhello;SupplierIntegerlenstr::length;// 3. 对象方法引用ClassName::instanceMethodFunctionString,StringupperString::toUpperCase;// 4. 构造方法引用ClassName::newSupplierArrayListStringlistSupplierArrayList::new;4. 性能注意点 ⚡4.1 Stream 不是万能的// ❌ 小数据量用 Stream 反而慢ListIntegerlistArrays.asList(1,2,3);intsumlist.stream().mapToInt(Integer::intValue).sum();// ✅ 简单循环可能更快intsum0;for(intn:list){sumn;}Stream 的开销创建 Stream 对象Lambda 包装链式调用建议小数据量1000用普通循环大数据量再用 Stream。4.2 避免在 Lambda 中捕获可变变量// ❌ 错误在 Lambda 中修改外部变量intsum0;list.stream().forEach(n-sumn);// 编译错误// ✅ 正确使用 reduceintsumlist.stream().reduce(0,Integer::sum);// ✅ 正确使用 AtomicIntegerAtomicIntegersumnewAtomicInteger();list.stream().forEach(n-sum.addAndGet(n));4.3 避免嵌套 Stream// ❌ 嵌套 Stream 性能差list.stream().flatMap(inner-inner.getSubList().stream()).collect(Collectors.toList());// ✅ 先提取再操作ListSubItemsubItemslist.stream().flatMap(inner-inner.getSubList().stream()).collect(Collectors.toList());4.4 用 findFirst 而不是 findAny// 需要有序结果时用 findFirstOptionalTfirstlist.stream().filter(...).findFirst();// 保证顺序// 不需要有序时用 findAnyOptionalTanylist.stream().filter(...).findAny();// 性能更好4.5 集合预分配容量// ❌ 不知道容量ListStringresultlist.stream().map(String::toUpperCase).collect(Collectors.toList());// ✅ 预分配容量ListStringresultlist.stream().map(String::toUpperCase).collect(Collectors.toCollection(()-newArrayList(list.size())));4.6 并行 Stream 的坑// ❌ 并行 Stream 不是万能的list.parallelStream().map(this::complexOperation)// 可能出问题.collect(Collectors.toList());// ✅ 并行 Stream 要保证线程安全// 1. 无状态操作// 2. 不修改共享变量// 3. 关联顺序无关并行 Stream 适用场景大数据量10000操作是纯函数无状态、无副作用不需要保证顺序5. 实战业务代码中的函数式编程 5.1 条件过滤// 之前ListUseractiveUsersnewArrayList();for(Useruser:users){if(user.isActive()user.getAge()18){activeUsers.add(user);}}// 之后ListUseractiveUsersusers.stream().filter(User::isActive).filter(user-user.getAge()18).collect(Collectors.toList());5.2 分组// 按状态分组MapOrderStatus,ListOrderordersByStatusorders.stream().collect(Collectors.groupingBy(Order::getStatus));// 按状态分组并计数MapOrderStatus,LongcountByStatusorders.stream().collect(Collectors.groupingBy(Order::getStatus,Collectors.counting()));5.3 转换// User - UserDTOListUserDTOdtosusers.stream().map(user-{UserDTOdtonewUserDTO();dto.setId(user.getId());dto.setName(user.getName());returndto;}).collect(Collectors.toList());5.4 聚合// 求和inttotalAgeusers.stream().mapToInt(User::getAge).sum();// 平均值doubleavgAgeusers.stream().mapToInt(User::getAge).average().orElse(0);// 统计信息IntSummaryStatisticsstatsusers.stream().mapToInt(User::getAge).summaryStatistics();5.5 复杂查询// 查找活跃用户按年龄排序取前 10 个ListUsertop10ActiveUsersusers.stream().filter(User::isActive).sorted(Comparator.comparingInt(User::getAge).reversed()).limit(10).collect(Collectors.toList());6. 常见面试题 6.1 Optional 和 null 有什么区别Optional 是容器可以包装可能为 null 的值Optional 提供了丰富的 API 避免空指针检查6.2 Stream 和 for 循环哪个快小数据量for 循环更快无额外开销大数据量Stream 更快并行处理简单操作for 循环复杂操作Stream 更简洁6.3 Lambda 会捕获什么Lambda 可以捕获静态变量实例变量通过 this局部变量必须是 final 或 effectively final6.4 什么是惰性求值中间操作不会立即执行只有遇到终端操作才会执行。6.5 parallelStream 的注意事项不是线程安全的不保证顺序适合大数据量、纯函数操作小结Optional适合方法返回值和链式调用避免 NPE但不要作为字段或参数Stream适合复杂数据处理中间操作惰性执行短路操作可以提前结束Lambda是匿名函数只能用于函数式接口方法引用是简写形式性能小数据量用 for 循环大数据量用 Stream并行 Stream 要保证线程安全函数式编程让代码更简洁但要避免过度使用下一篇021预告反射与注解Spring 里背后的影子——反射 API、注解定义与使用、Spring 中反射与注解的应用。

相关文章:

【020】Optional、Stream、Lambda:风格与性能注意点

写业务代码时,你可能已经用上了 Lambda 和 Stream: list.stream().filter(User::isActive).map(User::getName).collect(Collectors.toList());但有没有想过:Optional 什么时候该用、什么时候不该用?Stream 真的比 for 循环快吗&…...

从零到一:手把手教你理解车规级安全芯片HSM、SE与TrustZone的实战应用

从零到一:手把手教你理解车规级安全芯片HSM、SE与TrustZone的实战应用 在智能汽车电子系统设计中,安全芯片的选择与配置往往是工程师面临的第一个技术决策点。当我在参与某车企的域控制器开发项目时,曾遇到一个典型场景:ECU需要同…...

ROFL-Player:英雄联盟回放文件分析工具的终极指南

ROFL-Player:英雄联盟回放文件分析工具的终极指南 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player 你是否曾经想要快速查看英…...

【国家药监局NMPA最新指南解读】:Docker在IVD软件SaaS化中的强制配置项(2024Q3生效,错过即停运)

第一章:Docker在IVD软件SaaS化中的监管定位与合规边界在体外诊断(IVD)软件向SaaS模式演进过程中,Docker容器并非中立的技术载体,而是直接参与医疗器械质量管理体系(QMS)和监管合规链条的关键组件…...

Docker存储安全红线:7类未授权挂载风险场景曝光,CVE-2023-XXXX复现与零信任加固方案(含OCI合规检查表)

第一章:Docker存储安全红线:核心概念与威胁全景Docker 存储机制是容器运行时数据持久化与隔离的关键载体,其安全性直接影响镜像完整性、容器间数据隔离及宿主机系统防护能力。理解存储驱动(如 overlay2、aufs)、卷&…...

树、森林——树和森林的遍历(森林的遍历)

森林由多棵互不相交的树组成,遍历规则:按树的顺序依次遍历每一棵树 森林同样没有中序遍历,只有两种: 1. 森林先序遍历 访问第一棵树的根结点 先序遍历第一棵树的所有子树 依次先序遍历剩下所有树 对应关系:森林先序遍历…...

别再死记硬背了!用这5个真实UI案例,彻底搞懂HarmonyOS Flex布局的alignItems

别再死记硬背了!用这5个真实UI案例,彻底搞懂HarmonyOS Flex布局的alignItems 每次看到Flex布局的alignItems属性,你是不是也和我一样,对着文档里的Start、Center、End、Stretch、Baseline这几个选项发愁?明明每个单词都…...

Zotero Actions Tags终极指南:如何实现文献管理自动化工作流

Zotero Actions & Tags终极指南:如何实现文献管理自动化工作流 【免费下载链接】zotero-actions-tags Customize your Zotero workflow. 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-actions-tags Zotero Actions & Tags是一款专为Zotero用…...

【NI-DAQmx实战】从4-20mA到高精度:工业电流测量的选型与避坑指南

1. 4-20mA电流测量基础与工业应用 工业现场最头疼的问题之一,就是如何把传感器信号稳定可靠地传回控制室。我十年前第一次调试化工厂的液位变送器时,就吃过信号跳变的亏——当时用万用表量电压信号,20米的距离读数能差出10%。后来老师傅一句话…...

NVIDIA Riva多语言ASR系统部署与优化实战

1. NVIDIA Riva 多语言ASR系统概述NVIDIA Riva作为当前语音AI领域的标杆级解决方案,其最新2.18.0版本引入了多项突破性功能。这套GPU加速的语音AI微服务套件,现已整合了OpenAI Whisper和NVIDIA自研Canary架构,为多语言自动语音识别(ASR)和自动…...

构建跨设备游戏流媒体技术栈:Sunshine自托管服务器全解析与实践指南

构建跨设备游戏流媒体技术栈:Sunshine自托管服务器全解析与实践指南 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine Sunshine是一个开源的自托管游戏流媒体服务器&…...

如何用Bilibili-Evolved打造终极B站体验:新手完整指南

如何用Bilibili-Evolved打造终极B站体验:新手完整指南 【免费下载链接】Bilibili-Evolved 强大的哔哩哔哩增强脚本 项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved Bilibili-Evolved是一款功能强大的哔哩哔哩增强脚本,通过丰富的…...

收藏!码农的未来:AI时代,程序员如何逆袭成为“价值担当“?

AI正重构程序员行业,初级岗位需求下降30%,效率提升却未惠及所有人。高级程序员从"写代码者"转变为"AI审阅师",需掌握复杂系统协调与问题优化能力。AI虽能生成代码,但成本高昂且难达最优解,人类在业…...

别再踩坑了!Vue3子组件里用v-model绑定props,eslint报错no-mutating-props的两种实战解法

Vue3开发避坑指南:优雅解决v-model绑定props引发的eslint报错 在Vue3项目中使用Element Plus等UI库开发表单时,很多开发者会遇到一个看似合理却违反Vue设计原则的操作——直接在子组件中用v-model绑定父组件传递的props属性。这会导致eslint抛出vue/no-m…...

【C# .NET 11 AI推理加速黄金法则】:11个生产环境已验证的避坑点,错过=多花300%GPU成本

第一章:C# .NET 11 AI推理加速避坑总纲与成本影响模型在 C# .NET 11 环境中集成 AI 推理(如 ONNX Runtime、ML.NET 或自定义 TensorRT 封装)时,性能瓶颈常隐匿于运行时配置、内存生命周期与硬件亲和性策略之中。忽视这些细节将直接…...

收藏备用|2026最新版大模型学习指南,程序员破局35岁危机必看

最近在各平台刷到崩溃😭,好多码农兄弟疯狂吐槽: “谁懂啊家人们!传统开发卷麻了,天天熬大夜改bug,技术更新比翻书还快,越干越没底气” “35岁焦虑直接拉满!守着老技术混日子&#…...

CTF Pwn新手必看:用ROPgadget找pop rdi地址的保姆级教程(附常见坑点)

CTF Pwn实战指南:ROPgadget高效定位pop rdi的五大核心技巧 引言:为什么pop rdi是ROP链的黄金钥匙 在x64架构的CTF Pwn挑战中,pop rdi这条看似简单的指令往往成为解题的关键转折点。不同于x86时代通过栈传递参数的简单粗暴,x64体系…...

告别卡顿!用Unreal 5 Niagara + 顶点动画,轻松渲染上万“人群”的实战配置

告别卡顿!用Unreal 5 Niagara 顶点动画,轻松渲染上万“人群”的实战配置 当你在Unreal 5中尝试渲染大规模人群或生物群时,是否遇到过这样的困境:随着角色数量增加,帧率断崖式下跌,CPU和GPU负载飙升&#x…...

5G网络邻区同步与测量:从信号捕获到智能切换的实战解析

1. 5G邻区同步的核心流程解析 当你的手机从地铁站走到写字楼时,能保持视频通话不中断,背后正是邻区同步在发挥作用。这个过程就像搬家时先摸清新社区环境:要找到最近的超市(同步信道)、了解社区公告栏(广播…...

WebRTC 原理一篇讲透(从 0 到本质)

一、先讲结论(你先建立整体认知)WebRTC 本质 用 UDP 做的 P2P 实时通信 一套“打洞 协商”机制它不是一个“简单的库”,而是一整套机制:信令交换 NAT穿透 P2P连接 实时传输二、核心问题:两个设备为什么连不上&am…...

3分钟掌握Unlock-Music:免费音乐解密工具的完整使用指南

3分钟掌握Unlock-Music:免费音乐解密工具的完整使用指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: htt…...

终极指南:如何彻底卸载Windows自带的Microsoft Edge浏览器

终极指南:如何彻底卸载Windows自带的Microsoft Edge浏览器 【免费下载链接】EdgeRemover A PowerShell script that correctly uninstalls or reinstalls Microsoft Edge on Windows 10 & 11. 项目地址: https://gitcode.com/gh_mirrors/ed/EdgeRemover …...

STM32F103用CubeMX实现ADC欠采样:用800Hz采样率捕获1kHz正弦波(附工程源码)

STM32F103实战:用CubeMX配置ADC欠采样捕获1kHz正弦波 在嵌入式系统开发中,ADC采样是获取模拟信号的关键技术。传统采样理论告诉我们,采样频率必须至少是信号最高频率的两倍(奈奎斯特采样定理),但欠采样技术…...

5个你必须知道的UserAgent-Switcher实战技巧:轻松伪装你的浏览器身份

5个你必须知道的UserAgent-Switcher实战技巧:轻松伪装你的浏览器身份 【免费下载链接】UserAgent-Switcher A User-Agent spoofer browser extension that is highly configurable 项目地址: https://gitcode.com/gh_mirrors/us/UserAgent-Switcher 你是否曾…...

你的通信数据可靠吗?用STM32F103的硬件CRC模块给串口数据加个“保险”

STM32硬件CRC校验:为串口通信打造数据防护盾 在工业自动化、物联网设备通信等场景中,哪怕一个比特的错误都可能导致系统崩溃。去年我们团队就遇到过这样的案例:某生产线上的传感器数据因为电磁干扰发生位翻转,由于缺乏有效的校验机…...

蔚蓝档案自动化脚本:从手动肝游到智能托管的技术革命

蔚蓝档案自动化脚本:从手动肝游到智能托管的技术革命 【免费下载链接】blue_archive_auto_script 支持按轴凹总力战, 无缝制造三解, 用于实现蔚蓝档案自动化的程序( Steam已适配 ) 项目地址: https://gitcode.com/gh_mirrors/bl/blue_archive_auto_script 每…...

保姆级教程:在Ubuntu 20.04上为ARM开发板交叉编译GStreamer 1.14.0(含所有依赖库)

ARM嵌入式开发实战:Ubuntu 20.04下GStreamer 1.14.0全依赖链交叉编译指南 当我们需要在资源受限的ARM开发板上实现高效多媒体处理时,GStreamer往往是首选框架。但将其成功移植到嵌入式平台,需要穿越复杂的依赖迷宫。本文将手把手带你完成从零…...

终极指南:ExplorerPatcher一键解决Windows 10开始菜单关闭延迟问题

终极指南:ExplorerPatcher一键解决Windows 10开始菜单关闭延迟问题 【免费下载链接】ExplorerPatcher This project aims to enhance the working environment on Windows 项目地址: https://gitcode.com/GitHub_Trending/ex/ExplorerPatcher 你是否曾经遇到…...

Phi-4-mini-flash-reasoning零基础上手:无需代码的推理任务执行流程

Phi-4-mini-flash-reasoning零基础上手:无需代码的推理任务执行流程 1. 认识Phi-4-mini-flash-reasoning Phi-4-mini-flash-reasoning是一款专为文本推理任务优化的轻量级AI模型,特别适合需要逐步分析和逻辑推导的场景。不同于常见的聊天机器人&#x…...

终极指南:用Easy-Scraper在3分钟内掌握Rust网页数据提取

终极指南:用Easy-Scraper在3分钟内掌握Rust网页数据提取 【免费下载链接】easy-scraper Easy scraping library 项目地址: https://gitcode.com/gh_mirrors/ea/easy-scraper 想象一下,你正在构建一个新闻聚合应用,需要从几十个不同的网…...