Java中将包含嵌套列表的对象列表扁平化为单一元素列表的转换技巧

Java中将包含嵌套列表的对象列表扁平化为单一元素列表的转换技巧

本文探讨了在java中如何将一个包含嵌套列表的对象列表进行转换,使其生成一个新的列表,其中每个对象内部的嵌套列表只包含一个元素。文章详细介绍了三种实现方式:基于java 7及以前版本的传统循环方法、利用java 8至java 15的stream api结合`flatmap`操作,以及java 16及更高版本引入的`mapmulti`方法。通过示例代码和解释,帮助开发者理解并选择最适合其项目需求的列表转换策略。

在实际的软件开发中,我们经常会遇到需要处理复杂数据结构的情况,例如一个对象列表中包含另一个嵌套列表。有时,业务需求会要求我们将这种“一对多”的结构转换成“一对一”的扁平化结构,即对于原始列表中的每个对象,如果其嵌套列表包含多个元素,则需要创建多个新的父对象,每个新父对象只包含嵌套列表中的一个元素。

考虑以下Java类定义,其中Pmt对象包含一个Transaction对象的列表:

import java.util.List;import java.util.Collections; // 用于 Collections.singletonList// 假设 Transaction 是一个简单的POJOclass Transaction {    String transactionId;    String amount;    public Transaction(String transactionId, String amount) {        this.transactionId = transactionId;        this.amount = amount;    }    // Getters and Setters (省略)}// Pmt 类,包含一个Transaction列表class Pmt {    String id;    String b; // 其他属性    List trList;    // 构造函数:用于创建新的Pmt对象    public Pmt(String id, String b, List trList) {        this.id = id;        this.b = b;        this.trList = trList;    }    // 构造函数:用于复制现有Pmt对象的属性,并设置新的trList    public Pmt(Pmt originalPmt, List newTrList) {        this.id = originalPmt.getId();        this.b = originalPmt.getB();        this.trList = newTrList;    }    // Getters    public String getId() { return id; }    public String getB() { return b; }    public List getTrList() { return trList; }    @Override    public String toString() {        return "Pmt{" +               "id='" + id + ''' +               ", b='" + b + ''' +               ", trList=" + trList.stream().map(t -> t.transactionId).collect(java.util.stream.Collectors.joining(", ")) +               '}';    }}

我们的目标是将一个List转换为一个新的List,使得新列表中每个Pmt对象只包含一个Transaction。例如,如果原始列表中有5个Pmt对象,每个Pmt对象有2个Transaction,那么新列表将包含10个Pmt对象。每个新的Pmt对象将保留原始Pmt对象的id和b等属性。

下面将介绍几种在Java中实现这一转换的常用方法。

立即学习“Java免费学习笔记(深入)”;

1. Java 7 及以前版本 (传统循环方式)

在Java 7或更早的版本中,通常通过嵌套的for-each循环来实现这种一对多的列表转换。这种方法直观易懂,即使在Java 8及更高版本中也完全适用。

import java.util.ArrayList;import java.util.List;import static java.util.Collections.singletonList; // 静态导入public class ListTransformationLegacy {    public static List transformPmtList(List pmtList) {        List newList = new ArrayList();        for (Pmt p : pmtList) {            for (Transaction tr : p.getTrList()) {                // 为每个Transaction创建一个新的Pmt对象,并将其trList设置为只包含当前Transaction                newList.add(new Pmt(p.getId(), p.getB(), singletonList(tr)));            }        }        return newList;    }    public static void main(String[] args) {        // 示例数据        List originalPmtList = new ArrayList();        Pmt pmt1 = new Pmt("P001", "B1", List.of(new Transaction("T001A", "100"), new Transaction("T001B", "200")));        Pmt pmt2 = new Pmt("P002", "B2", List.of(new Transaction("T002A", "300")));        originalPmtList.add(pmt1);        originalPmtList.add(pmt2);        System.out.println("原始列表:");        originalPmtList.forEach(System.out::println);        List transformedList = transformPmtList(originalPmtList);        System.out.println("n转换后的列表 (Java 7 风格):");        transformedList.forEach(System.out::println);    }}

优点:

逻辑清晰,易于理解和调试。兼容所有Java版本。

缺点:

代码相对冗长,可读性可能不如Stream API在处理复杂转换时简洁。

2. Java 8 – Java 15 (Stream API – flatMap 方法)

Java 8引入的Stream API为集合操作提供了更函数式、更简洁的表达方式。对于一对多的转换,flatMap操作是理想的选择。flatMap可以将一个流中的每个元素转换为另一个流,然后将所有这些流扁平化为一个单一的流。

import java.util.List;import java.util.stream.Collectors;import static java.util.Collections.singletonList;public class ListTransformationStreamFlatMap {    public static List transformPmtList(List pmtList) {        return pmtList.stream()            // 对于每个Pmt对象,将其trList转换为一个Transaction流            .flatMap(p -> p.getTrList().stream()                // 对于每个Transaction,创建一个新的Pmt对象                .map(tr -> new Pmt(p.getId(), p.getB(), singletonList(tr))))            // 将所有新的Pmt对象收集到一个列表中            .collect(Collectors.toList());    }    public static void main(String[] args) {        // 示例数据 (同上)        List originalPmtList = new ArrayList();        Pmt pmt1 = new Pmt("P001", "B1", List.of(new Transaction("T001A", "100"), new Transaction("T001B", "200")));        Pmt pmt2 = new Pmt("P002", "B2", List.of(new Transaction("T002A", "300")));        originalPmtList.add(pmt1);        originalPmtList.add(pmt2);        System.out.println("原始列表:");        originalPmtList.forEach(System.out::println);        List transformedList = transformPmtList(originalPmtList);        System.out.println("n转换后的列表 (Java 8-15 Stream API 风格 - flatMap):");        transformedList.forEach(System.out::println);    }}

优点:

代码更加简洁、声明式,符合函数式编程风格。易于并行化处理(通过.parallelStream())。可读性在熟悉Stream API的开发者中很高。

缺点:

对于不熟悉Stream API的开发者,理解可能需要一定的学习曲线。

3. Java 16 及更高版本 (Stream API – mapMulti 方法)

Java 16引入了mapMulti方法,它提供了一种更灵活的方式来处理一对多(或零对多)的转换,有时可以替代flatMap,并且在某些场景下可能更高效。mapMulti允许你通过一个Consumer来“发出”零个、一个或多个元素到下游流中。

import java.util.List;import java.util.function.Consumer;import static java.util.Collections.singletonList;public class ListTransformationStreamMapMulti {    public static List transformPmtList(List pmtList) {        return pmtList.stream()            // 使用mapMulti进行一对多转换            .mapMulti((Pmt p, Consumer c) -> {                // 对于当前Pmt对象的每个Transaction                p.getTrList().forEach(tr ->                    // 发出一个新的Pmt对象到下游流                    c.accept(new Pmt(p.getId(), p.getB(), singletonList(tr))));            })            // 将流中的所有元素收集到一个列表中            .toList(); // Java 16+ 的便捷收集方法    }    public static void main(String[] args) {        // 示例数据 (同上)        List originalPmtList = new ArrayList();        Pmt pmt1 = new Pmt("P001", "B1", List.of(new Transaction("T001A", "100"), new Transaction("T001B", "200")));        Pmt pmt2 = new Pmt("P002", "B2", List.of(new Transaction("T002A", "300")));        originalPmtList.add(pmt1);        originalPmtList.add(pmt2);        System.out.println("原始列表:");        originalPmtList.forEach(System.out::println);        List transformedList = transformPmtList(originalPmtList);        System.out.println("n转换后的列表 (Java 16+ Stream API 风格 - mapMulti):");        transformedList.forEach(System.out::println);    }}

优点:

在某些场景下,mapMulti可能比flatMap更高效,因为它避免了创建中间流的开销。提供了更大的灵活性,可以根据条件发出或不发出元素。代码意图明确,直接表达了“对于每个输入,可以产生零个、一个或多个输出”。

缺点:

仅适用于Java 16及更高版本。对于初次接触的开发者,其Consumer回调的模式可能需要适应。

注意事项与总结

不可变性原则: 在所有示例中,我们都强调创建新的Pmt对象而不是修改原始对象。这符合函数式编程的不可变性原则,有助于避免副作用,使代码更健壮、更易于测试和理解。Collections.singletonList(): 这个方法用于创建一个只包含一个元素的不可变列表。这比new ArrayList(List.of(tr))更高效且内存占用更少,特别适合这种只包含单个元素的场景。空列表处理: 如果原始Pmt对象的trList为空,上述Stream API方法(flatMap和mapMulti)将自动跳过这些Pmt对象,不会生成新的Pmt。传统循环方式也同样处理。选择合适的版本:对于Java 7及更早的项目,传统循环是唯一的选择。对于Java 8-15的项目,flatMap通常是推荐的简洁且强大的解决方案。对于Java 16及更高版本,mapMulti提供了一个可能更高效和灵活的替代方案,值得尝试。

通过以上三种方法,开发者可以根据项目所使用的Java版本和个人偏好,灵活地将包含嵌套列表的对象列表扁平化为每个对象只包含一个元素的结构。选择最适合的方案,可以有效提升代码的可读性、维护性和性能。

以上就是Java中将包含嵌套列表的对象列表扁平化为单一元素列表的转换技巧的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/204199.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
怎样在VSCode中比较两个文件的差异?
上一篇 2025年11月1日 22:58:33
监控工具(Prometheus+Grafana)配置
下一篇 2025年11月1日 22:58:36

相关推荐

  • Yii 框架执行数据库事务时遇到异常怎么处理?

    在 yii 框架中处理数据库事务异常时,应使用 try-catch 块捕获异常并回滚事务。具体方法包括:1) 使用 try-catch 块捕获 exception 和 throwable 异常,并在异常发生时回滚事务;2) 处理事务嵌套,确保只有最外层事务真正提交或回滚;3) 设置事务隔离级别以处理…

    2026年8月28日
    300
  • 使用Flag变量实现Java菜单循环与返回

    本文将介绍如何在Java程序中使用flag变量控制菜单的循环和返回。通过设置和判断flag变量的值,可以实现从子菜单返回主菜单的功能,避免不必要的菜单重复显示,提升用户体验。本文将提供代码示例,详细解释flag变量的工作原理,并给出使用注意事项。 在Java程序中,经常需要构建交互式的菜单界面,让用…

    2026年8月28日
    000
  • 投资领域掀起大模型“淘金热”,AI的“财商”有多高?

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ AI赋能财富管理:机遇与挑战并存 国产AI大模型的兴起,正深刻改变着财富管理行业的面貌。“AI理财”已成为投资者关注的焦点,但其可靠性及潜在风险也引发广泛讨论。本文将探讨AI在投资理财领域的应用…

    2026年8月28日
    000
  • 如何在 Yii 项目中引入 GraphQL?

    在 yii 项目中引入 graphql 可以通过以下步骤实现:1. 定义 schema,描述数据结构和查询操作;2. 实现解析器,映射查询到数据获取逻辑;3. 处理请求并生成响应。通过这些步骤,开发者可以在 yii 中集成 graphql api,提供灵活的数据获取方式。 引言 在现代 Web 开发…

    2026年8月28日
    300
  • 抖音店铺体验分受什么影响?体验分80分要多少单

    短视频平台抖音逐渐成为人们生活中不可或缺的一部分。抖音店铺作为抖音电商的重要组成部分,其店铺体验分的高低直接关系到店铺的销量和口碑。抖音店铺体验分受哪些因素影响呢?本文将为您揭秘影响抖音店铺体验分的关键因素。 一、商品质量 商品质量是影响抖音店铺体验分的首要因素。优质的产品能够满足消费者的需求,提高…

    2026年8月28日
    100
  • 清华大学2025年将适度扩招本科生 重点培养“AI+”拔尖创新人才

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 清华大学宣布将适度扩大本科招生规模,计划于2025年新增约150个本科招生名额。同时,学校将成立一所新的本科通识书院,专注培养人工智能与其他学科交叉融合的复合型人才,以满足国家战略需求和社会发展…

    2026年8月28日
    900
  • 黄仁勋:英伟达最后入局半导体但永远不晚,自己若今年毕业将爱上 AI

    7 月 16 日消息,根据新浪科技报道,英伟达 CEO 黄仁勋在今日下午的媒体采访中提到,英伟达是较晚成立的半导体公司之一,但他强调“入场虽晚,却从不嫌迟”。 黄仁勋说道:“我不是先行者,而是后来者,所以永远不会太晚。因为如果你是第一个进入市场的人,你有独特的优势;而作为最后一个进入的人,同样也能找…

    2026年8月28日
    100
  • ThinkPHP 性能优化:10个提升速度的技巧

    提升thinkphp应用性能的10个技巧包括:1.优化数据库查询,减少查询次数;2.使用缓存策略,降低数据库负载;3.实施延迟加载,减少初始加载时间;4.进行批量操作,减少数据库连接次数;5.避免n+1查询问题,使用关联查询;6.优化模板渲染,使用缓存模板;7.启用编译模式,提升启动速度;8.优化日…

    2026年8月28日
    100
  • 深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新

    深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新

    提到折叠屏手机,三星无疑是行业开拓者。自2008年开始探索折叠屏技术,到2011年推出首款原型机,再到2019年正式发布首款商用折叠屏设备galaxy fold,三星在该领域深耕超过15年,持续推动形态创新,逐步确立了其行业领先地位。如今,全新推出的galaxy z fold7,在轻薄化、性能与耐用…

    2026年8月28日 用户投稿
    000
  • Laravel 队列(Queue)与任务调度:提升应用性能

    laravel 应用可以通过队列和任务调度提升性能。1) 队列用于异步处理耗时任务,提高响应速度。2) 任务调度用于自动执行定时任务,实现自动化操作。 引言 当你深陷于 Laravel 应用的开发中,性能问题总会如影随形。如何让你的应用在高并发下依然保持优雅的姿态?答案之一就是巧妙地利用 Larav…

    2026年8月28日
    100
  • ZXing生成二维码水印变黑白的原因及解决方法是什么?

    解决zxing生成二维码水印变黑白的问题 在使用ZXing库生成二维码并用Thumbnailator库添加水印时,常常遇到水印颜色变黑白的困扰。这是因为ZXing生成的二维码默认位深度为1(黑白),而水印图片通常是彩色图像。Thumbnailator在叠加水印时,会根据底图(二维码)的位深度调整输出…

    2026年8月28日
    100
  • 四个月内至少有九大旗舰手机发布 苹果领衔 华为缺席?

    四个月内至少有九大旗舰手机发布 苹果领衔 华为缺席?四个月内至少有九大旗舰手机发布 苹果领衔 华为缺席?四个月内至少有九大旗舰手机发布 苹果领衔 华为缺席?四个月内至少有九大旗舰手机发布 苹果领衔 华为缺席?

    7月16日,数码闲聊站透露,2025年9月至10月,预计至少有九大旗舰系列手机发布。 iPhone 17系列:包含iPhone 17、iPhone 17 Air、iPhone 17 Pro和iPhone 17 Pro Max四款机型,9月初发布; 小米16系列:首批包含小米16、小米16 Pro两款…

    2026年8月28日 用户投稿
    100
  • Laravel API 开发:RESTful 设计与 JWT 认证

    在 laravel 中构建 restful api 并使用 jwt 进行用户认证的方法如下:1. 使用 laravel 的路由系统定义 restful api 操作。2. 安装并配置 tymon/jwt-auth 包来处理 jwt 认证。3. 在 user 模型中实现 jwtsubject 接口。4…

    2026年8月28日
    100
  • 如何解决PHPStan分析中的常见错误?使用symplify/phpstan-extensions可以!

    可以通过以下地址学习composer:学习地址 在使用PHPStan进行代码分析时,错误信息的处理一直是个难题。特别是当你需要快速定位错误并将其忽略时,传统的错误格式并不友好。幸运的是,symplify/phpstan-extensions提供了更人性化的错误格式和扩展功能,让你能够更高效地处理这些…

    用户投稿 2026年8月28日
    100
  • 向实同行,共创融合新生态!拓维信息受邀参加2025中国联通合作伙伴大会

    7月18日至19日,2025中国联通合作伙伴大会将在上海世博中心隆重举行,大会以“向实同行,共创融合新生态”为主题。作为国内最早专注运营商领域发展的it科技企业之一,同时也是中国联通的重要战略合作伙伴,拓维信息将联合旗下湘江鲲鹏深度参与此次盛会,并展示其“ai+鸿蒙”软硬一体化智能产品与创新解决方案…

    2026年8月28日
    100
  • C# 进程间通讯

    一、进程间通信的方式 1)共享内存 包括:内存映射文件、共享内存DLL、剪切板。 2)命名管道和匿名管道 3)消息通信 4)利用代理方法,例如SOCKET、配置文件、注册表方式等。 方法一:通信。 进程间通信的方式多种多样,常用的有共享内存(如内存映射文件、共享内存DLL、剪切板等)、命名管道和匿名…

    2026年8月28日
    200
  • Java OpenCV人脸检测与照片编辑:如何用Java和OpenCV实现人脸检测及照片尺寸、背景调整?

    基于Java和OpenCV的人脸检测及照片编辑 本文介绍如何利用Java和OpenCV库实现人脸检测,并对符合条件的照片进行尺寸、背景调整等编辑操作。 用户需提供一张穿着深色衣物、背景为白墙的上半身照片。系统将调整照片尺寸,并根据人脸宽度、发际线到照片顶部的距离以及双眼内眼角距离等参数,判断人脸区域…

    2026年8月28日
    100
  • RuoYi框架代码生成器如何适配SQL Server数据库?

    RuoYi-SQLServer 代码生成器适配:从 MySQL 到 SQL Server 的迁移 ruoyi框架的sqlserver版本(ruoyi-sqlserver)原本只支持mysql数据库的代码自动生成功能,现在需要将其扩展到sql server。这篇文章将探讨如何修改代码,实现sql se…

    用户投稿 2026年8月28日
    100
  • Yii 框架如何支持 WebSocket 实时通信?

    yii 框架本身不直接支持 websocket,但可以通过扩展实现。1. 安装扩展库(如 yii2-websocket 或 ratchet)。2. 配置 websocket 服务器。3. 实现 websocket 逻辑。通过这些步骤,可以在 yii 中实现实时通信功能。 引言 WebSocket 作…

    2026年8月28日
    100
  • 如何解决Laravel批量插入和更新的问题?使用mavinoo/laravel-batch可以!

    可以通过以下地址学习composer:学习地址 在开发laravel项目时,我遇到一个常见但棘手的问题:如何高效地进行批量数据的插入和更新。默认的eloquent模型虽然强大,但对于大批量数据处理,效率往往不尽如人意。我尝试过一些手动优化,但效果有限。直到我发现了mavinoo/laravel-ba…

    用户投稿 2026年8月28日
    100

发表回复

登录后才能评论
关注微信