Java 集合数据处理技巧:使用 Stream API 实现多种操作
在 Java 开发中,对集合数据进行处理是非常常见的需求,例如去重、排序、分组、求和等。Java 8 引入的 Stream API 为我们提供了一种简洁、高效的方式来处理集合数据。本文将详细介绍如何使用 Stream API 实现多种集合数据处理操作,并给出相应的代码示例。
1. List 根据某个属性去重
在处理 List 数据时,有时需要根据对象的某个属性进行去重。可以使用 TreeSet 和 Stream 来实现这一功能。以下是示例代码:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;// 定义 SKU 类
class SKU {private String gid;public SKU(String gid) {this.gid = gid;}public String getGid() {return gid;}
}public class ListDistinctByProperty {public static void main(String[] args) {List<SKU> skuList = new ArrayList<>();skuList.add(new SKU("1"));skuList.add(new SKU("2"));skuList.add(new SKU("1"));ArrayList<SKU> skus = skuList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SKU::getGid))), ArrayList::new));skus.forEach(sku -> System.out.println(sku.getGid()));}
}
在上述代码中,首先创建了一个 SKU 类,包含 gid 属性。然后使用 Stream 对 skuList 进行处理,通过 Collectors.toCollection 将其转换为 TreeSet,利用 TreeSet 的特性根据 gid 去重,最后再将 TreeSet 转换为 ArrayList。
2. 指定字段排序
2.1 升序排序
可以使用 Stream 的 sorted 方法和 Comparator.comparing 来实现指定字段的升序排序。以下是示例代码:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;// 定义 Order 类
class Order {private long createTime;public Order(long createTime) {this.createTime = createTime;}public long getCreateTime() {return createTime;}
}public class ListSortAsc {public static void main(String[] args) {List<Order> orderList = new ArrayList<>();orderList.add(new Order(3));orderList.add(new Order(1));orderList.add(new Order(2));List<Order> sortedList = orderList.stream().sorted(Comparator.comparing(Order::getCreateTime)).collect(Collectors.toList());sortedList.forEach(order -> System.out.println(order.getCreateTime()));}
}
2.2 降序排序
如果需要降序排序,只需在 Comparator.comparing 后调用 reversed 方法。以下是示例代码:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;// 定义 Order 类
class Order {private long createTime;public Order(long createTime) {this.createTime = createTime;}public long getCreateTime() {return createTime;}
}public class ListSortDesc {public static void main(String[] args) {List<Order> orderList = new ArrayList<>();orderList.add(new Order(3));orderList.add(new Order(1));orderList.add(new Order(2));List<Order> sortedList = orderList.stream().sorted(Comparator.comparing(Order::getCreateTime).reversed()).collect(Collectors.toList());sortedList.forEach(order -> System.out.println(order.getCreateTime()));}
}
2.3 null 排前面
如果需要将 null 值排在前面,可以使用 Comparator.nullsFirst 方法。以下是示例代码:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;// 定义 LuckyBoysVo 类
class LuckyBoysVo {private Date usageTime;public LuckyBoysVo(Date usageTime) {this.usageTime = usageTime;}public Date getUsageTime() {return usageTime;}
}public class ListSortNullFirst {public static void main(String[] args) {List<LuckyBoysVo> luckyBoysList = new ArrayList<>();luckyBoysList.add(new LuckyBoysVo(new Date(2000)));luckyBoysList.add(new LuckyBoysVo(null));luckyBoysList.add(new LuckyBoysVo(new Date(1000)));List<LuckyBoysVo> luckyBoysVoList = luckyBoysList.stream().sorted(Comparator.comparing(LuckyBoysVo::getUsageTime, Comparator.nullsFirst(Date::compareTo))).collect(Collectors.toList());luckyBoysVoList.forEach(vo -> System.out.println(vo.getUsageTime()));}
}
3. 指定字段相同,指定值计算和
可以使用 Collectors.groupingBy 方法对数据进行分组,然后使用 reduce 方法计算相同字段对应的值的和。以下是示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;// 定义 ExportAgentVo 类
class ExportAgentVo {private String dealCode;private String agentId;private String goodsId;private String goodName;private int count;private String name;private String address;public ExportAgentVo(String dealCode, String agentId, String goodsId, String goodName, int count, String name, String address) {this.dealCode = dealCode;this.agentId = agentId;this.goodsId = goodsId;this.goodName = goodName;this.count = count;this.name = name;this.address = address;}public String getDealCode() {return dealCode;}public String getAgentId() {return agentId;}public String getGoodsId() {return goodsId;}public String getGoodName() {return goodName;}public int getCount() {return count;}public String getName() {return name;}public String getAddress() {return address;}
}public class ListSumByField {public static void main(String[] args) {List<ExportAgentVo> exportAgentVoList = new ArrayList<>();exportAgentVoList.add(new ExportAgentVo("1", "A", "G1", "Good1", 10, "Name1", "Addr1"));exportAgentVoList.add(new ExportAgentVo("2", "A", "G1", "Good1", 20, "Name1", "Addr1"));List<ExportAgentVo> exportAgentVoListResult = new ArrayList<>();exportAgentVoList.stream().collect(Collectors.groupingBy(o -> (o.getGoodsId() + o.getAgentId()), Collectors.toList())).forEach((id, transfer) -> {transfer.stream().reduce((a, b) ->new ExportAgentVo(a.getDealCode(),a.getAgentId(),a.getGoodsId(),a.getGoodName(),a.getCount() + b.getCount(), a.getName(), a.getAddress())).ifPresent(exportAgentVoListResult::add);});exportAgentVoListResult.forEach(vo -> System.out.println(vo.getCount()));}
}
4. 指定字段相同,计算相同个数
可以使用 Collectors.groupingBy 和 Collectors.counting 方法来计算指定字段相同的个数。以下是示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;// 定义 TkDetailMaskLayerMapping 类
class TkDetailMaskLayerMapping {private String maskId;public TkDetailMaskLayerMapping(String maskId) {this.maskId = maskId;}public String getMaskId() {return maskId;}
}public class ListCountByField {public static void main(String[] args) {List<TkDetailMaskLayerMapping> list = new ArrayList<>();list.add(new TkDetailMaskLayerMapping("M1"));list.add(new TkDetailMaskLayerMapping("M1"));list.add(new TkDetailMaskLayerMapping("M2"));Map<String, Long> map = list.stream().collect(Collectors.groupingBy(TkDetailMaskLayerMapping::getMaskId, Collectors.counting()));map.forEach((key, value) -> System.out.println(key + ": " + value));}
}
5. 指定字段分组
可以使用 Collectors.groupingBy 方法对 List 进行指定字段分组。以下是示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;// 定义 ExportAgentVo 类
class ExportAgentVo {private String agentId;public ExportAgentVo(String agentId) {this.agentId = agentId;}public String getAgentId() {return agentId;}
}public class ListGroupByField {public static void main(String[] args) {List<ExportAgentVo> exportAgentVoListResult = new ArrayList<>();exportAgentVoListResult.add(new ExportAgentVo("A1"));exportAgentVoListResult.add(new ExportAgentVo("A2"));exportAgentVoListResult.add(new ExportAgentVo("A1"));Map<String, List<ExportAgentVo>> exportAgentVoMap = exportAgentVoListResult.stream().collect(Collectors.groupingBy(ExportAgentVo::getAgentId));exportAgentVoMap.forEach((key, value) -> System.out.println(key + ": " + value.size()));}
}
6. 分组并求和
可以使用 Collectors.groupingBy 和 Collectors.summingInt 方法对数据进行分组并求和。以下是示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;// 定义 ExportGoodsProcurementDetailVo 类
class ExportGoodsProcurementDetailVo {private String supplierName;private String agentId;private String goodsId;private int count;public ExportGoodsProcurementDetailVo(String supplierName, String agentId, String goodsId, int count) {this.supplierName = supplierName;this.agentId = agentId;this.goodsId = goodsId;this.count = count;}public String getSupplierName() {return supplierName;}public String getAgentId() {return agentId;}public String getGoodsId() {return goodsId;}public int getCount() {return count;}
}public class ListGroupAndSum {public static void main(String[] args) {List<ExportGoodsProcurementDetailVo> goodsProcurementDetailVos = new ArrayList<>();goodsProcurementDetailVos.add(new ExportGoodsProcurementDetailVo("S1", "A1", "G1", 10));goodsProcurementDetailVos.add(new ExportGoodsProcurementDetailVo("S1", "A1", "G1", 20));ExportGoodsProcurementDetailVo exportGoodsProcurementDetailVo = new ExportGoodsProcurementDetailVo("S1", "A1", "", 0);ExportGoodsProcurementDetailVo exportGoBeerVo = new ExportGoodsProcurementDetailVo("", "A1", "", 0);Map<String, Integer> goodCountMap = goodsProcurementDetailVos.stream().filter(a -> a.getSupplierName().equals(exportGoodsProcurementDetailVo.getSupplierName())&& a.getAgentId().equals(exportGoBeerVo.getAgentId())).collect(Collectors.groupingBy(ExportGoodsProcurementDetailVo::getGoodsId,Collectors.summingInt(ExportGoodsProcurementDetailVo::getCount)));goodCountMap.forEach((key, value) -> System.out.println(key + ": " + value));}
}
7. List 转 Map
可以使用 Collectors.toMap 方法将 List 转换为 Map。需要注意的是,如果集合对象有重复的 key,会报错 Duplicate key,可以使用 (k1, k2) -> k1 来处理重复 key 的情况。以下是示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;// 定义 CustomerDetailResp 类
class CustomerDetailResp {private String dept;private String members;public CustomerDetailResp(String dept, String members) {this.dept = dept;this.members = members;}public String getDept() {return dept;}public String getMembers() {return members;}
}// 定义 Apple 类
class Apple {private int id;public Apple(int id) {this.id = id;}public int getId() {return id;}
}public class ListToMap {public static void main(String[] args) {List<CustomerDetailResp> result = new ArrayList<>();result.add(new CustomerDetailResp("D1", "M1"));result.add(new CustomerDetailResp("D2", "M2"));Map<String, String> map1 = result.stream().collect(Collectors.toMap(CustomerDetailResp::getDept, CustomerDetailResp::getMembers));Map<String, CustomerDetailResp> map2 = result.stream().collect(Collectors.toMap(CustomerDetailResp::getDept, CustomerDetailResp -> CustomerDetailResp));List<Apple> appleList = new ArrayList<>();appleList.add(new Apple(1));appleList.add(new Apple(1));Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a, (k1, k2) -> k1));}
}
8. List 转 String
可以使用 Google Guava 库的 Joiner 类将 List 转换为 String。以下是示例代码:
import com.google.common.base.Joiner;
import java.util.ArrayList;
import java.util.List;public class ListToString {public static void main(String[] args) {List<String> itemNoList = new ArrayList<>();itemNoList.add("1");itemNoList.add("2");itemNoList.add("3");String join = Joiner.on(',').join(itemNoList);System.out.println(join);}
}
9. String 转 List
可以使用 Arrays.stream 和 Collectors.toList 方法将 String 转换为 List。以下是示例代码:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class StringToList {public static void main(String[] args) {String sales = "1,2,3,2";List<String> saleList = Arrays.stream(sales.split(",")).distinct().collect(Collectors.toList());saleList.forEach(System.out::println);}
}
通过以上示例,我们可以看到 Java 8 的 Stream API 为集合数据处理提供了非常强大和便捷的功能。合理使用这些功能可以大大提高代码的可读性和开发效率。本文示例已涵盖日常开发中90%的集合处理场景,建议根据具体业务需求灵活组合使用。对于更复杂的操作,可结合Collectors.joining、mapping等收集器实现。
相关文章:
Java 集合数据处理技巧:使用 Stream API 实现多种操作
在 Java 开发中,对集合数据进行处理是非常常见的需求,例如去重、排序、分组、求和等。Java 8 引入的 Stream API 为我们提供了一种简洁、高效的方式来处理集合数据。本文将详细介绍如何使用 Stream API 实现多种集合数据处理操作,并给出相…...
OSI 参考模型和 TCP/IP 参考模型
数据通信是很复杂的,很难在一个协议中完成所有功能。因此在制定协议时经常采用的思路是将复杂的数据通信功能由若干协议分别完成,然后将这些协议按照一定的方式组织起来。最典型的是采用分层的方式来组织协议,每一层都有一套清晰明确的功能和…...
【kafka系列】broker
目录 Broker 接收生产者消息和返回消息给消费者的流程逻辑分析 Broker 处理生产者消息的核心流程 Broker 处理消费者消息的核心流程 关键点总结 Broker 接收生产者消息和返回消息给消费者的流程逻辑分析 Broker 处理生产者消息的核心流程 接收请求 Broker 的 SocketServer …...
OpenCV机器学习(5)逻辑回归算法cv::ml::LogisticRegression
OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::ml::LogisticRegression 是 OpenCV 机器学习模块中的一个类,用于实现逻辑回归算法。逻辑回归是一种广泛应用于分类问题的统计方法,特别适合二分类任务。…...
FreeRTOS第12篇:系统的“绿色通道”——中断管理与临界区
文/指尖动听知识库-星愿 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:深入FreeRTOS内核:从原理到实战的嵌入式开发指南 引言:嵌入式系统的“紧急电话” 想象你正在主持一场重要会议:大部分时间按议程推进(任务执行),但偶尔会有紧急来电(硬…...
Spring Boot01(注解、)---java八股
Spring Boot中常用注解及其底层实现 1、SpringBootApplication注解: SpringBootApplication注解:这个注解标识了一个SpringBoot工程,它实际上是另外三个注解的组合,这三个注解是: aSpringBootConfiguration:…...
SD NAND 的 SDIO在STM32上的应用详解(上篇)
目录 上篇: 一.SDIO简介 二.SD卡简介/内部结构 1.SD卡/SD NAND引脚 2.SD卡寄存器 3.FLASH存储器 三.SDIO总线拓扑 中篇: 四.SDIO功能框图(重点) 1.SDIO适配器 2.控制单元 3.命令通道(重点) 4.数…...
基于图像处理的裂缝检测与特征提取
一、引言 裂缝检测是基础设施监测中至关重要的一项任务,尤其是在土木工程和建筑工程领域。随着自动化技术的发展,传统的人工巡检方法逐渐被基于图像分析的自动化检测系统所取代。通过计算机视觉和图像处理技术,能够高效、精确地提取裂缝的几何特征,如长度、宽度、方向、面…...
执行pnpm run dev报错:node:events:491 throw er; // Unhandled ‘error‘ event的解决方案
vite搭建的vue项目,使用pnpm包管理工具,执行pnpm run dev,报如下错误: 报错原因: pnpm依赖安装不完整,缺少esbuild.exe文件,导致无法执行启动命令。 解决方案: 根据错误提示中提到…...
JavaScript数组-数组的概念
在JavaScript编程中,数组(Array)是一种非常重要的数据结构,它允许我们将多个值存储在一个单独的变量中。数组可以包含任意类型的元素,如数字、字符串、对象甚至是其他数组,并提供了丰富的内置方法来操作这些…...
「软件设计模式」建造者模式(Builder)
深入解析建造者模式:用C打造灵活对象构建流水线 引言:当对象构建遇上排列组合 在开发复杂业务系统时,你是否经常面对这样的类:它有20个成员变量,其中5个是必填项,15个是可选项。当用户需要创建豪华套餐A&…...
uniapp 安卓10+ 选择并上传文件
plus.io.chooseFile({title: 选择文件,filetypes: [mp3], // 允许的文件类型multiple: false, // 是否允许多选}, (res) > {console.log(虚拟路径666:, res);var arr[{name: files,uri: res.files[0],}]let obj {"tableName": "mingmen_daily_mi…...
【第1章:深度学习概览——1.6 深度学习框架简介与选择建议】
嘿,各位老铁们,今天咱们来一场深度学习框架的深度探索之旅。在这个充满无限可能的深度学习时代,深度学习框架就像是连接理论与实践的桥梁,帮助我们从算法设计走向实际应用。随着技术的飞速发展,深度学习框架的选择变得越来越多样化,每一种框架都有其独特的优势和适用场景…...
在 Android 上自定义编译 FFmpeg
1. 自定义编译 FFmpeg 1.1 准备工作 在开始编译之前,您需要以下工具和环境: 操作系统:Linux 或 macOS(推荐)。NDK:Android Native Development Kit(NDK)。FFmpeg 源码:从 FFmpeg 官方网站 或 GitHub 仓库下载。编译脚本:用于自动化编译过程。1.2 安装依赖工具 在 …...
网页制作02-html,css,javascript初认识のhtml的文字与段落标记
用一首李白的将进酒,对文字与段落标记进行一个简单的介绍演示: 目录 一、标题字 1、标题字标记h 2、标题字对其属性align 二、文本基本标记 1、字体属性face 2、字号属性size 3、颜色属性 Color 三、文本格式化标记 1、粗体标记 b ,strong 2、…...
FFmpeg源码:url_find_protocol函数分析
一、url_find_protocol函数的定义 url_find_protocol函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/avio.c中: static const struct URLProtocol *url_find_protocol(const char *filename) {const URLProt…...
一.数据治理理论架构
1、数据治理核心思想: 数据治理理论架构图描绘了一个由顶层设计、管控机制、核心领域和管理系统四个主要部分组成的数据治理框架。它旨在通过系统化的方法,解决数据治理机制缺失引发的业务和技术问题,并最终提升企业的数据管理水平。 数据治…...
CentOS上远程连接SSH常用操作命令整理
1.SSH服务状态查询,查看SSH服务是否正在运行的命令 sudo systemctl status sshd 2.SSH服务的启动及设置系统启动时自动运行命令 sudo systemctl start sshd sudo systemctl enable sshd 3.SSH服务的重启命令 sudo systemctl restart sshd 4.SSH的主要配置文件是/…...
PHP基础部分
但凡是和输入、写入相关的一定要预防别人植入恶意代码! HTML部分 语句格式 <br> <hr> 分割符 <p>插入一行 按住shift 输入! 然后按回车可快速输入html代码(VsCode需要先安装live server插件) html:<h1>标题 数字越大越往后</h1> <p…...
人工智能 - 主动视觉可能就是你所需要的:在双臂机器人操作中探索主动视觉
AV-ALOHA 系统使用用于 AV 的 VR 耳机实现直观的数据收集,并且 用于作的 VR 控制器或引线臂。这有助于捕捉全身和头部 远程作我们的真实和模拟系统的运动,记录来自 6 个的视频 不同的摄像头,并为我们的 AV 仿制学习策略提供训练数据。 加州大…...
乘法逆元是什么
逆元(Inverse Element)是数学中的一个概念,特别是在模运算中非常重要。逆元的定义依赖于具体的运算和集合。在编程算法中,逆元通常指的是模数下的乘法逆元。 1. 逆元的定义 在模运算中,给定一个整数 ( a ) 和一个模数…...
DeepSeek 助力 Vue 开发:打造丝滑的日期选择器(Date Picker),未使用第三方插件
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
Python编程中,async/await/asyncio分别是干啥的?
在Python异步编程中,async、await和asyncio是三个核心概念。它们共同构成了Python处理高并发I/O密集型任务的解决方案。本文将通过代码实例解析它们的作用和用法。 一、异步编程基础 1.1 同步 vs 异步 同步编程:代码按顺序执行,遇到I/O操作(如网络请求、文件读写)时会阻塞…...
Kafka偏移量管理全攻略:从基础概念到高级操作实战
#作者:猎人 文章目录 前言:概念剖析kafka的两种位移消费位移消息的位移位移的提交自动提交手动提交 1、使用--to-earliest重置消费组消费指定topic进度2、使用--to-offset重置消费offset3、使用--to-datetime策略指定时间重置offset4、使用--to-current…...
一周学会Flask3 Python Web开发-Debug模式开启
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 默认情况,项目开发是普通模式,也就是你修改了代码,必须重启项目,新代码才生效&…...
单例模式、构造函数、左值右值
拷贝构造函数 简单的说就是——用一个对象构造另外一个对象 class Myclass {public:int d0;Myclass(int d_){d d_}; //常用的构造函数Myclass(Myclass c) //拷贝构造函数{d c.d;} }; //对比 class Myclass {public:int d0;Myclass(int d_){d d_}; //常用的构造函数Myclass…...
java练习(28)
ps:练习来自力扣 给定一个二叉树,判断它是否是平衡二叉树 // 定义二叉树节点类 class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.va…...
【信息学奥赛一本通 C++题解】1285:最大上升子序列和
信息学奥赛一本通(C版)在线评测系统 基础算法 第一节 动态规划的基本模型 1285:最大上升子序列和 “最大上升子序列和”问题课堂讲解 1. 理解题意 同学们,想象我们有一串数字,就像一串彩色的珠子,每个珠子…...
深入了解 CSS 常用的样式
在网页开发中,CSS(层叠样式表)起着至关重要的作用,它可以让我们的网页变得更加美观和易于阅读。除了一些特定场景下的 CSS 样式,还有许多其他常用的 CSS 样式,下面就让我们一起来详细了解一下。 一、文本相…...
Web安全|渗透测试|网络安全
基础入门(P1-P5) p1概念名词 1.1域名 什么是域名? 域名:是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时对计算机的定位标识(有时也指地理位置)。 什么是二级域名多级域名&am…...
