首页 > Java > java教程 > 正文

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

DDD
发布: 2025-10-12 13:28:02
原创
406人浏览过

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

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

引言:数据转换的挑战

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

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

数据模型定义

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

1. Value 枚举

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

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

public enum Value {
    VALUE1,
    VALUE2,
    VALUE3
}
登录后复制

2. Person 实体类

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

腾讯智影-AI数字人
腾讯智影-AI数字人

基于AI数字人能力,实现7*24小时AI数字人直播带货,低成本实现直播业务快速增增,全天智能在线直播

腾讯智影-AI数字人 73
查看详情 腾讯智影-AI数字人
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<String, List<Person>>
        Map<String, List<Person>> 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<String, List<Person>>转换为List<PersonDto>:

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

        List<PersonDto> resultDtos = personsData.values().stream()
                // 1. 获取所有Person列表的Stream
                // Stream<List<Person>> -> Stream<Person>
                .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<PersonDto>
                .collect(Collectors.toList());

        // 打印结果
        resultDtos.forEach(System.out::println);
    }
登录后复制

解释:

  • personsData.values().stream(): 首先,我们从Map中获取所有List<Person>的集合,并将其转换为一个Stream<List<Person>>。
  • .flatMap(List::stream): 这一步是关键。由于我们有一个Stream,其中每个元素本身又是一个List<Person>,flatMap操作用于将这些内部列表“扁平化”成一个单一的Stream<Person>。这意味着,所有Person对象现在都在一个流中,可以进行统一处理。
  • .map(person -> new PersonDto(...)): 接下来,对于Stream<Person>中的每一个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<PersonDto>中。

完整示例代码

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<String, List<Person>>
        Map<String, List<Person>> 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<PersonDto> resultDtos = personsData.values().stream()
                .flatMap(List::stream) // 扁平化 Stream<List<Person>> 到 Stream<Person>
                .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) { ... },这会增加代码的复杂性。考虑是否可以通过设计更具体的子类或使用泛型来

以上就是Java Stream API实现复杂Map到DTO的转换与数据整形的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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