0

0

Java Stream API实现复杂Map到DTO的转换与数据整形

DDD

DDD

发布时间:2025-10-12 13:28:02

|

423人浏览过

|

来源于php中文网

原创

Java Stream API实现复杂Map到DTO的转换与数据整形

本文详细阐述如何利用java 8 stream api,将一个包含嵌套列表和异构数据类型的`map>`结构高效转换为扁平化的`list`。教程涵盖数据模型定义、stream操作(`flatmap`、`map`)的运用、日期格式化以及异构数据类型的处理,旨在提供一个清晰、专业的实践指南。

引言:数据转换的挑战

在现代Java应用开发中,数据转换是常见的任务。我们经常需要将一种复杂的数据结构(例如,嵌套的Map或List)转换成另一种更适合业务逻辑或前端展示的简单结构(通常是数据传输对象DTO)。当源数据中包含异构类型(如同一字段存储整数、字符串或日期)时,这一转换过程会变得更具挑战性。

本教程将以一个具体场景为例:将一个Map>结构转换为List。原始Person对象中的某个字段(表示“值”)可能包含不同类型的数据,并且日期字段需要进行格式化。我们将利用Java 8的Stream API来优雅地解决这一问题。

数据模型定义

首先,我们需要定义涉及到的数据模型,包括枚举、原始实体类和目标DTO类。

1. Value 枚举

这个枚举用于表示Person对象中的一个分类标签,例如不同的事件类型。

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

public enum Value {
    VALUE1,
    VALUE2,
    VALUE3
}

2. Person 实体类

Person类代表原始数据结构中的个体记录。注意其中valueData字段被定义为Object类型,以容纳不同类型的数据(整数、字符串、日期)。eventDate字段使用LocalDate存储。

知了zKnown
知了zKnown

知了zKnown:致力于信息降噪 / 阅读提效的个人知识助手。

下载
import java.time.LocalDate;

public class Person {
    private String id; // 例如 "p1", "p2"
    private Value tag; // 例如 VALUE1, VALUE2
    private Object valueData; // 异构数据,例如 10, "Text", LocalDate
    private LocalDate eventDate; // 例如 2000-10-10
    private String message;

    public Person(String id, Value tag, Object valueData, LocalDate eventDate, String message) {
        this.id = id;
        this.tag = tag;
        this.valueData = valueData;
        this.eventDate = eventDate;
        this.message = message;
    }

    // Getters
    public String getId() { return id; }
    public Value getTag() { return tag; }
    public Object getValueData() { return valueData; }
    public LocalDate getEventDate() { return eventDate; }
    public String getMessage() { return message; }

    @Override
    public String toString() {
        return "Person{" +
               "id='" + id + '\'' +
               ", tag=" + tag +
               ", valueData=" + valueData +
               ", eventDate=" + eventDate +
               ", message='" + message + '\'' +
               '}';
    }
}

3. PersonDto 数据传输对象

PersonDto是转换后的目标对象,它扁平化了Person数据,并根据需求调整了字段类型(例如,将LocalDate转换为String)。

public class PersonDto {
    private Value tag; // 对应 Person.tag
    private String id; // 对应 Person.id
    private String date; // 对应 Person.eventDate (格式化后)
    private Object result; // 对应 Person.valueData (异构数据)

    public PersonDto(Value tag, String id, String date, Object result) {
        this.tag = tag;
        this.id = id;
        this.date = date;
        this.result = result;
    }

    // Getters
    public Value getTag() { return tag; }
    public String getId() { return id; }
    public String getDate() { return date; }
    public Object getResult() { return result; }

    @Override
    public String toString() {
        return "PersonDto{" +
               "tag=" + tag +
               ", id='" + id + '\'' +
               ", date='" + date + '\'' +
               ", result=" + result +
               '}';
    }
}

Stream API 实现数据转换

核心转换逻辑将利用Stream API的flatMap和map操作。

1. 初始化数据

为了演示,我们首先创建一些模拟数据:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class DataTransformer {

    static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");

    public static void main(String[] args) {
        // 模拟原始数据 Map>
        Map> personsData = new HashMap<>();

        // Person p1 records
        personsData.put("p1", Arrays.asList(
            new Person("p1", Value.VALUE1, 10, LocalDate.of(2000, 10, 10), "Message"),
            new Person("p1", Value.VALUE2, "Text", LocalDate.of(2000, 10, 10), "Message"),
            new Person("p1", Value.VALUE3, LocalDate.of(2000, 11, 11), LocalDate.of(2000, 10, 10), "Message")
        ));

        // Person p2 records
        personsData.put("p2", Arrays.asList(
            new Person("p2", Value.VALUE1, 20, LocalDate.of(2000, 10, 10), "Message"),
            new Person("p2", Value.VALUE2, "Text", LocalDate.of(2000, 10, 10), "Message"),
            new Person("p2", Value.VALUE3, LocalDate.of(2000, 11, 12), LocalDate.of(2000, 10, 10), "Message")
        ));

        // ... (调用转换方法)
    }
}

2. Stream 转换逻辑

现在,我们将personsData这个Map>转换为List

    public static void main(String[] args) {
        // ... (数据初始化)

        List resultDtos = personsData.values().stream()
                // 1. 获取所有Person列表的Stream
                // Stream> -> Stream
                .flatMap(List::stream)
                // 2. 将每个Person对象映射为PersonDto
                .map(person -> new PersonDto(
                        person.getTag(), // 映射 Person.tag 到 PersonDto.tag
                        person.getId(),   // 映射 Person.id 到 PersonDto.id
                        formatter.format(person.getEventDate()), // 格式化 Person.eventDate 到 PersonDto.date
                        person.getValueData() // 映射 Person.valueData (异构Object) 到 PersonDto.result
                ))
                // 3. 收集结果到List
                .collect(Collectors.toList());

        // 打印结果
        resultDtos.forEach(System.out::println);
    }

解释:

  • personsData.values().stream(): 首先,我们从Map中获取所有List的集合,并将其转换为一个Stream>。
  • .flatMap(List::stream): 这一步是关键。由于我们有一个Stream,其中每个元素本身又是一个List,flatMap操作用于将这些内部列表“扁平化”成一个单一的Stream。这意味着,所有Person对象现在都在一个流中,可以进行统一处理。
  • .map(person -> new PersonDto(...)): 接下来,对于Stream中的每一个Person对象,我们使用map操作将其转换成一个PersonDto实例。
    • 在PersonDto的构造函数中,我们根据Person对象的属性进行赋值。
    • person.getTag()直接映射到PersonDto.tag。
    • person.getId()直接映射到PersonDto.id。
    • formatter.format(person.getEventDate()):这里使用了DateTimeFormatter来将LocalDate类型的eventDate格式化为指定的String类型,并映射到PersonDto.date。
    • person.getValueData():由于Person.valueData被定义为Object类型以处理异构数据,它被直接映射到PersonDto.result,保持其原始类型。
  • .collect(Collectors.toList()): 最后,collect操作将处理后的所有PersonDto对象收集到一个新的List中。

完整示例代码

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

// Value Enum
enum Value {
    VALUE1,
    VALUE2,
    VALUE3
}

// Person Entity Class
class Person {
    private String id;
    private Value tag;
    private Object valueData;
    private LocalDate eventDate;
    private String message;

    public Person(String id, Value tag, Object valueData, LocalDate eventDate, String message) {
        this.id = id;
        this.tag = tag;
        this.valueData = valueData;
        this.eventDate = eventDate;
        this.message = message;
    }

    public String getId() { return id; }
    public Value getTag() { return tag; }
    public Object getValueData() { return valueData; }
    public LocalDate getEventDate() { return eventDate; }
    public String getMessage() { return message; }

    @Override
    public String toString() {
        return "Person{" +
               "id='" + id + '\'' +
               ", tag=" + tag +
               ", valueData=" + valueData +
               ", eventDate=" + eventDate +
               ", message='" + message + '\'' +
               '}';
    }
}

// PersonDto DTO Class
class PersonDto {
    private Value tag;
    private String id;
    private String date;
    private Object result;

    public PersonDto(Value tag, String id, String date, Object result) {
        this.tag = tag;
        this.id = id;
        this.date = date;
        this.result = result;
    }

    public Value getTag() { return tag; }
    public String getId() { return id; }
    public String getDate() { return date; }
    public Object getResult() { return result; }

    @Override
    public String toString() {
        return "PersonDto{" +
               "tag=" + tag +
               ", id='" + id + '\'' +
               ", date='" + date + '\'' +
               ", result=" + result +
               '}';
    }
}

public class DataTransformer {

    static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");

    public static void main(String[] args) {
        // 模拟原始数据 Map>
        Map> personsData = new HashMap<>();

        // Person p1 records
        personsData.put("p1", Arrays.asList(
            new Person("p1", Value.VALUE1, 10, LocalDate.of(2000, 10, 10), "Message"),
            new Person("p1", Value.VALUE2, "Text", LocalDate.of(2000, 10, 10), "Message"),
            new Person("p1", Value.VALUE3, LocalDate.of(2000, 11, 11), LocalDate.of(2000, 10, 10), "Message")
        ));

        // Person p2 records
        personsData.put("p2", Arrays.asList(
            new Person("p2", Value.VALUE1, 20, LocalDate.of(2000, 10, 10), "Message"),
            new Person("p2", Value.VALUE2, "Text", LocalDate.of(2000, 10, 10), "Message"),
            new Person("p2", Value.VALUE3, LocalDate.of(2000, 11, 12), LocalDate.of(2000, 10, 10), "Message")
        ));

        // 使用 Stream API 进行转换
        List resultDtos = personsData.values().stream()
                .flatMap(List::stream) // 扁平化 Stream> 到 Stream
                .map(person -> new PersonDto(
                        person.getTag(),
                        person.getId(),
                        formatter.format(person.getEventDate()), // 格式化日期
                        person.getValueData() // 处理异构数据
                ))
                .collect(Collectors.toList()); // 收集结果

        // 打印转换后的 DTO 列表
        System.out.println("转换后的 PersonDto 列表:");
        resultDtos.forEach(System.out::println);
    }
}

注意事项与总结

  1. 异构数据类型处理: 当某个字段需要存储多种类型的数据时,将其定义为Object是一个常见的策略。然而,在后续使用这些数据时,需要进行类型检查或强制类型转换,例如if (dto.getResult() instanceof Integer) { ... },这会增加代码的复杂性。考虑是否可以通过设计更具体的子类或使用泛型来

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

309

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

222

2025.10.31

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

778

2023.08.22

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

778

2023.08.22

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

782

2023.07.31

python中的format是什么意思
python中的format是什么意思

python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

434

2024.06.27

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.9万人学习

Java 教程
Java 教程

共578课时 | 52.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号