JDK8中的 Stream流式编程用法优化(工具类在文章最后)

Java从JDK8起提供了Stream流这个功能,于是项目里出现了大量基于Stream流的写法。随着项目的进行,慢慢的代码中铺天盖地的都是下面的写法:

 List<User> userList = null;if (condition) {userList = new ArrayList<>();userList.add(User.builder().id(1L).name("张三").age(25).build());userList.add(User.builder().id(2L).name("李四").age(30).build());userList.add(User.builder().id(3L).name("王五").age(40).build());}...省略了的业务逻辑...List<User> users = userList.stream().filter(it-> it.getAge() > 28).collect(Collectors.toList());System.out.println(users);

上面的代码中,构建了一个包含3个User对象的List,然后取出了其中age大于28的User对象构成了新的List。相信如果在日常工作和学习中写过了大量的类似的代码,很容易能看出问题来,userList会出现为空的情况,这时候是很容易触发空指针异常的。所以我们在使用stream前通常都是需要做非空判断的。于是,优化后的代码出现了:

List<User> userList = null;
if (condition) {userList = new ArrayList<>();userList.add(User.builder().id(1L).name("张三").age(25).build());userList.add(User.builder().id(2L).name("李四").age(30).build());userList.add(User.builder().id(3L).name("王五").age(40).build());
}...省略了的业务逻辑...
if (userList != null) {List<User> users = userList.stream().filter(it-> it.getAge() > 28).collect(Collectors.toList());System.out.println(users);
}

更近一步,还可以这样写:

List<User> userList = null;
if (condition) {userList = new ArrayList<>();userList.add(User.builder().id(1L).name("张三").age(25).build());userList.add(User.builder().id(2L).name("李四").age(30).build());userList.add(User.builder().id(3L).name("王五").age(40).build());
}...省略了的业务逻辑...
List<User> users = Optional.of(userList).orElse(List.of()).stream().filter(it-> it.getAge() > 28).collect(Collectors.toList());
System.out.println(users);

到了这里,这已经是一段比较常规的业务代码了,但是它真的很丑有没有。作为一个业务研发人员,我为什么要考虑这么多呢?我不需要关注List是怎么转换成stream的,同样的,我也不关心为什么在使用完stream以后还要collect。于是,我将上面的流式代码封装成了工具类,上面的代码可以简化为:

List<User> userList = null;
if (condition) {userList = new ArrayList<>();userList.add(User.builder().id(1L).name("张三").age(25).build());userList.add(User.builder().id(2L).name("李四").age(30).build());userList.add(User.builder().id(3L).name("王五").age(40).build());
}...省略了的业务逻辑...
List<User> users = Streams.filter(userList, it-> it.getAge() > 28);
System.out.println(users);

同样的,也支持其他操作:

//返回年龄大于28的用户列表
List<User> filterUsers = Streams.filter(userList, it -> it.getAge() > 28);//返回年龄大于28的用户的姓名列表
List<String> filterNames = Streams.toList(userList, it -> it.getAge() > 28, User::getName);//返回年龄大于28的用户的姓名作为key, 年龄只作为value的map
Map<String, Integer> filterNameAndAgeMap = Streams.toMap(userList, it -> it.getAge() > 28, User::getName, User::getAge);//返回所有用户的姓名列表
List<String> allUserNames = Streams.toList(userList, User::getName);//返回所有用户的姓名作为key, 用户信息只作为value的map
Map<String, User> allUserMap = Streams.mappingToMap(userList, User::getName);//返回所有用户的姓名作为key, 年龄作为value的map
Map<String, Integer> nameAndAgeMap = Streams.toMap(userList, User::getName, User::getAge);//返回年龄大于28的第一个用户, 如果找不到则使用默认值
User user = Streams.findFirstOrElse(userList, it-> it.getAge() > 28, new User());//返回年龄大于28的第一个用户, 如果找不到则抛出异常
User user2 = Streams.findFirstOrThrow(userList, it-> it.getAge() > 28, "未找到符合条件的数据");

最后附上工具类源码供各位取用:

package com.zlyx.common.util;import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;public class Streams {public static <T> List<T> filter(List<T> dataList, Predicate<T> filter) {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).collect(Collectors.toList());}public static <T> Set<T> filter(Set<T> dataList, Predicate<T> filter) {return Optional.of(dataList).orElse(Set.of()).stream().filter(filter).collect(Collectors.toSet());}public static <T> T findFirstOrThrow(List<T> dataList) throws Exception {return findFirstOrThrow(dataList, "未找到符合条件的数据");}public static <T> T findFirstOrThrow(List<T> dataList, String errorMsg) throws Exception {return findFirstOrThrow(dataList, Objects::nonNull, errorMsg);}public static <T> T findFirstOrThrow(List<T> dataList, Predicate<T> filter, String errorMsg) throws Exception {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).findFirst().orElseThrow(() -> new Exception(errorMsg));}public static <T> T findFirstOrElse(List<T> dataList, T defaultValue) {return findFirstOrElse(dataList, Objects::nonNull, defaultValue);}public static <T> T findFirstOrElse(List<T> dataList, Predicate<T> filter, T defaultValue) {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).findFirst().orElse(defaultValue);}public static <T, R> R findAnyOrNull(List<T> dataList, Function<T, R> mapper) {return Optional.of(dataList).orElse(List.of()).stream().map(mapper).filter(Objects::nonNull).findAny().orElse(null);}public static <T, R> R findAnyOrThrow(List<T> dataList, Function<T, R> mapper, String errorMsg) throws Exception {return Optional.of(dataList).orElse(List.of()).stream().map(mapper).filter(Objects::nonNull).findAny().orElseThrow(() -> new Exception(errorMsg));}public static <T, R> Set<R> toSet(List<T> dataList, Function<T, R> mapper) {return toSet(dataList, Objects::nonNull, mapper);}public static <T, R> Set<R> toSet(List<T> dataList, Predicate<T> filter, Function<T, R> mapper) {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).map(mapper).collect(Collectors.toSet());}public static <T, R> List<R> toList(List<T> dataList, Function<T, R> mapper) {return toList(dataList, Objects::nonNull, mapper);}public static <T, R> List<R> toList(List<T> dataList, Predicate<T> filter, Function<T, R> mapper) {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).map(mapper).distinct().collect(Collectors.toList());}public static <T, K> Map<K, T> mappingToMap(List<T> dataList, Function<T, K> keyMapper) {return mappingToMap(dataList, Objects::nonNull, keyMapper);}public static <T, K> Map<K, T> mappingToMap(List<T> dataList, Predicate<T> filter, Function<T, K> keyMapper) {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).collect(Collectors.toMap(keyMapper, it -> it, (v1, v2) -> v2));}public static <T, K, V> Map<K, V> toMap(List<T> dataList, Function<T, K> keyMapper, Function<T, V> valueMapper) {return toMap(dataList, Objects::nonNull, keyMapper, valueMapper);}public static <T, K, V> Map<K, V> toMap(List<T> dataList, Predicate<T> filter, Function<T, K> keyMapper, Function<T, V> valueMapper) {return Optional.of(dataList).orElse(List.of()).stream().filter(filter).collect(Collectors.toMap(keyMapper, valueMapper));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/80933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud生态与技术选型指南:如何构建高可用的微服务系统?

引言&#xff1a;为什么选择Spring Cloud&#xff1f; 作为全球开发者首选的微服务框架&#xff0c;Spring Cloud凭借其开箱即用的组件、与Spring Boot的无缝集成&#xff0c;以及活跃的社区生态&#xff0c;成为企业级微服务架构的基石。但在实际项目中&#xff0c;如何从众多…

Android清单文件

清单文件AndroidManifest.xml AndroidManifest.xml 配置清单文件是 每个 Android 应用的配置中心&#xff0c;系统在安装和运行应用时&#xff0c;首先会读取它。 它是 Android 应用的 “说明书”&#xff0c;主要作用是&#xff1a; 功能说明声明应用组件比如 Activity、Se…

大语言模型与人工智能:技术演进、生态重构与未来挑战

目录 技术演进:从专用AI到通用智能的跃迁核心能力:LLM如何重构AI技术栈应用场景:垂直领域的技术革命生态关系:LLM与AI技术矩阵的协同演进挑战局限:智能天花板与伦理困境未来趋势:从语言理解到世界模型1. 技术演进:从专用AI到通用智能的跃迁 1.1 三次技术浪潮的跨越 #me…

SC3000智能相机-自动存图

1、需求:SC3000智能相机开机自动存图。相机自带的相机存储空间有限,预留存图需要开启SCMVS、并手动点存图。如果工人忘了开启则不会存图,导致生产严重失误! 2、方法:利用相机提供的FTP协议,将图自动存到本地。 1、在本地建立FTP服务器。 (1)win10默认开启了FTP服务器…

Wan2.1 文生视频 支持批量生成、参数化配置和多语言提示词管理

Wan2.1 文生视频 支持批量生成、参数化配置和多语言提示词管理 flyfish 设计 一个基于 Wan2.1 文本到视频模型的自动化视频生成系统。 文件关系图 script.py ├── 读取 → config.json │ ├── 模型配置 → 加载AI模型 │ ├── 生成参数 → 控制生成质量 │ └…

Flannel后端为UDP模式下,分析数据包的发送方式——tun设备(三)

在分析 Kubernetes 环境中 Flannel UDP 模式的数据包转发时&#xff0c;我们提到 flannel.1 是一个 TUN 设备&#xff0c;它在数据包处理中起到了关键作用。 什么是 TUN 设备&#xff1f; TUN 设备&#xff08;Tunnel 设备&#xff09;是 Linux 系统中一种虚拟网络接口&#x…

Java中创建线程的几种方式

目录 Java 创建线程的几种方式 一、继承 Thread 类 核心原理 实现步骤 代码示例 简化写法&#xff08;Lambda 表达式&#xff09; 优缺点 二、实现 Runnable 接口 核心原理 实现步骤 代码示例 简化写法&#xff08;Lambda 表达式&#xff09; 优缺点分析 三、实现…

[Git] 基本操作及用户配置

文章目录 现在所讲&#xff0c;全部是本地Git仓库&#xff0c;不是远程仓库&#xff01;Git是版本控制工具&#xff0c;而并非只能用远程仓库的版本控制工具&#xff01; 什么是“仓库”&#xff08;Repository&#xff09;&#xff1f;创建一个 Git 本地仓库&#xff1a;git i…

layui 介绍

layui&#xff08;谐音&#xff1a;类 UI) 是一套开源的 Web UI 解决方案&#xff0c;采用自身经典的模块化规范&#xff0c;并遵循原生 HTML/CSS/JS 的开发方式&#xff0c;极易上手&#xff0c;拿来即用。其风格简约轻盈&#xff0c;而组件优雅丰盈&#xff0c;从源代码到使用…

笔记:NAT

一、NAT 的基本概念 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09; 是一种在 IP 网络中重新映射 IP 地址的技术&#xff0c;主要用于解决 IPv4 地址短缺问题&#xff0c;同时提供一定的网络安全防护作用。 功能&#xff1a; 将内部网络&am…

cursor/vscode启动项目connect ETIMEDOUT 127.0.0.1:xx

现象&#xff1a; 上午正常使用cursor/vscode&#xff0c;因为需要写前端安装了nodejs16.20和vue2&#xff0c;结果下午启动前端服务无法访问&#xff0c;浏览器一直转圈。接着测试运行最简单的flask服务&#xff0c;vscode报错connect ETIMEDOUT 127.0.0.1:xx&#xff0c;要么…

EXO分布式部署deepseek r1

EXO 是一个支持分布式 AI 计算的框架&#xff0c;可以用于在多个设备&#xff08;包括 Mac Studio&#xff09;上运行大语言模型&#xff08;LLM&#xff09;。以下是联调 Mac Studio 512GB 的步骤&#xff1a; 安装 EXO • 从 EXO GitHub 仓库 下载源码或使用 git clone 获取…

python训练营打卡第30天

模块和库的导入 知识点回顾&#xff1a; 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑&#xff1a;找到根目录&#xff08;python解释器的目录和终端的目录不一致&#xff09; 一、导入官方库 1.标准导入&#xff1a;导入整个库 import mathprint(&quo…

Unity 多时间源Timer定时器实战分享:健壮性、高效性、多线程安全与稳定性能全面解析

简介 Timer 是一个 Unity 环境下高效、灵活的定时任务调度系统&#xff0c;支持以下功能&#xff1a; •支持多种时间源&#xff08;游戏时间 / 非缩放时间 / 真实时间&#xff09; •支持一次性延迟执行和重复执行 •提供 ID、回调、目标对象等多种查询和销毁方式 •内建…

深入理解Docker和K8S

深入理解Docker和K8S Docker 是大型架构的必备技能&#xff0c;也是云原生核心。Docker 容器化作为一种轻量级的虚拟化技术&#xff0c;其核心思想&#xff1a;将应用程序及其所有依赖项打包在一起&#xff0c;形成一个可移植的单元。 容器的本质是进程&#xff1a; 容器是在…

docker中使用openresty

1.为什么要使用openresty 我这边是因为要使用1Panel&#xff0c;第一个最大的原因&#xff0c;就是图方便&#xff0c;比较可以一键安装。但以前一直都是直接安装nginx。所以需要一个过度。 2.如何查看openResty使用了nginx哪个版本 /usr/local/openresty/nginx/sbin/nginx …

CSS【详解】弹性布局 flex

适用场景 一维&#xff08;行或列&#xff09;布局 基本概念 包裹所有被布局元素的父元素为容器 所有被布局的元素为项目 项目的排列方向&#xff08;垂直/水平&#xff09;为主轴 与主轴垂直的方向交交叉轴 容器上启用 flex 布局 将容器的 display 样式设置为 flex 或 i…

全能视频处理工具介绍说明

软件介绍 本文介绍的软件是FFmpeg小白助手&#xff0c;它是一款视频处理工具。 使用便捷性 这款FFmpeg小白助手无需安装&#xff0c;解压出来就能够直接投入使用。 主要功能概述 该工具主要具备格式转换、文件裁剪、文件压缩、文件合并这四大功能。 格式转换能力 软件支持…

Linux中的DNS的安装与配置

DNS简介 DNS&#xff08;DomainNameSystem&#xff09;是互联网上的一项服务&#xff0c;它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网。 DNS使用的是53端口 通常DNS是以UDP这个较快速的数据传输协议来查询的&#xff0c;但是没有查…

tshark的使用技巧(wireshark的命令行,类似tcpdump):转换格式,设置filter

tshark的使用技巧&#xff08;wireshark的命令行&#xff0c;类似tcpdump&#xff09;&#xff1a;转换格式&#xff0c;设置filter tshark一般在 C:\Program Files\Wireshark 使用管理员权限 打开cmd tshark -D 列出支持抓包的接口&#xff1a; c:\Program Files\Wiresh…