0

0

Java Stream 数据分组后如何优化JSON响应:排除分组字段的两种策略

霞舞

霞舞

发布时间:2025-11-22 14:18:06

|

979人浏览过

|

来源于php中文网

原创

Java Stream 数据分组后如何优化JSON响应:排除分组字段的两种策略

本文旨在探讨在java应用中,当使用stream api对数据进行分组(例如按部门分组员工)后,如何在最终的json响应中移除作为分组键的字段。我们将介绍两种主要策略:利用jackson库的`@jsonignore`注解直接忽略字段,以及创建独立的响应dto并结合`collectors.mapping`进行二次转换。通过这两种方法,可以有效优化api响应结构,避免数据冗余,提升客户端处理效率和用户体验。

在现代Web服务开发中,数据传输对象(DTO)是连接后端业务逻辑与前端展示的重要桥梁。当我们需要对一组数据进行分组展示时,例如将员工列表按部门分组,通常会使用Java Stream API的Collectors.groupingBy操作。然而,一个常见需求是,虽然我们按某个字段(如department)进行了分组,但在分组后的每个具体数据项中,该字段却显得冗余,因为它已经作为分组的键存在。本文将提供两种专业的解决方案来解决这一问题,从而生成更简洁、更优化的JSON响应。

假设我们有如下员工记录接口:

public interface EmployeesRecord {
    String getName();
    String getDepartment();
    String getEmail();
}

并且有一个DTO用于将员工列表按部门分组:

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public record EmployeesDto(Map<String, List<EmployeesRecord>> employeesRecordList) {

    public static EmployeesDto from(List<EmployeesRecord> data) {
        Map<String, List<EmployeesRecord>> mappedEmployees =
                data.stream().collect(Collectors.groupingBy(EmployeesRecord::getDepartment));
        return new EmployeesDto(mappedEmployees);
    }
}

当前的响应会包含每个员工记录中的department字段,如下所示:

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

{
    "employeesRecordList": {
        "finance": [
            {
                "name": "Jerry Doe",
                "department": "finance", // 冗余字段
                "email": "jerry.doe@example.com"
            }
            // ...
        ]
        // ...
    }
}

我们的目标是移除分组后的员工对象中的department字段,使其响应更为精简。

策略一:使用 @JsonIgnore 注解

Jackson 是 Java 中广泛使用的 JSON 处理库。它提供了一个 @JsonIgnore 注解,可以直接标记在字段或 getter 方法上,指示 Jackson 在序列化(转换为 JSON)时忽略该字段。这是最简单、最直接的解决方案,适用于当某个字段在任何 JSON 响应中都不需要出现,或者其主要作用仅限于内部处理或分组键的场景。

天工大模型
天工大模型

中国首个对标ChatGPT的双千亿级大语言模型

下载

实现步骤

  1. 在 EmployeesRecord 接口(或其实现类)的 getDepartment() 方法上添加 @JsonIgnore 注解。

示例代码

import com.fasterxml.jackson.annotation.JsonIgnore;

public interface EmployeesRecord {
    String getName();

    @JsonIgnore // 标记此方法对应的字段在JSON序列化时被忽略
    String getDepartment();

    String getEmail();
}

如果 EmployeesRecord 是一个类而不是接口,你可以直接在字段或 getter 方法上添加注解:

import com.fasterxml.jackson.annotation.JsonIgnore;

public class Employee implements EmployeesRecord {
    private String name;
    private String department;
    private String email;

    // 构造函数、setter等省略

    @Override
    public String getName() { return name; }

    @Override
    @JsonIgnore // 标记此方法对应的字段在JSON序列化时被忽略
    public String getDepartment() { return department; }

    @Override
    public String getEmail() { return email; }
}

优点

  • 简单快捷:只需添加一个注解,无需修改数据处理逻辑。
  • 全局性:一旦标记,该字段在所有通过 Jackson 序列化的场景中都会被忽略。

缺点

  • 侵入性:修改了原始数据模型(接口或类),可能影响其他需要该字段的 JSON 序列化场景。
  • 不够灵活:如果某些场景需要 department 字段,而另一些不需要,这种方法就无法满足。

策略二:创建专用响应 DTO 并进行二次映射

这种策略是更推荐的“分离关注点”的做法。它涉及到创建一个新的 DTO,该 DTO 仅包含你希望在最终响应中出现的字段。然后,在数据分组之后,将原始的 EmployeesRecord 对象转换为这个新的 DTO。这种方法提供了更高的灵活性和更清晰的数据模型分离。

实现步骤

  1. 定义一个新的 DTO,例如 EmployeeDetailsDto,它只包含 name 和 email 字段。
  2. 修改 EmployeesDto.from 方法,在 Collectors.groupingBy 之后,使用 Collectors.mapping 对每个分组内的元素进行二次转换。

示例代码

首先,定义一个只包含 name 和 email 的 DTO:

public record EmployeeDetailsDto(String name, String email) {
    // 构造函数可以方便地从 EmployeesRecord 创建
    public EmployeeDetailsDto(EmployeesRecord record) {
        this(record.getName(), record.getEmail());
    }
}

然后,修改 EmployeesDto 的 from 方法:

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public record EmployeesDto(Map<String, List<EmployeeDetailsDto>> employeesRecordList) {

    public static EmployeesDto from(List<EmployeesRecord> data) {
        Map<String, List<EmployeeDetailsDto>> mappedEmployees =
                data.stream().collect(
                    Collectors.groupingBy(
                        EmployeesRecord::getDepartment, // 按 department 分组
                        Collectors.mapping(
                            EmployeeDetailsDto::new, // 将每个 EmployeesRecord 映射为 EmployeeDetailsDto
                            Collectors.toList()       // 收集为 List
                        )
                    )
                );
        return new EmployeesDto(mappedEmployees);
    }
}

优点

  • 关注点分离:原始的 EmployeesRecord 保持不变,其完整性不受影响。
  • 高度灵活:可以根据不同的API响应需求创建不同的 DTO,实现更精细的控制。
  • 清晰的契约:API响应的结构由 EmployeeDetailsDto 明确定义,易于理解和维护。
  • 可测试性:转换逻辑独立,易于单元测试。

缺点

  • 代码量增加:需要额外定义一个 DTO 类,并修改 Stream 收集逻辑,相对于 @JsonIgnore 而言,代码量略有增加。
  • 轻微的性能开销:多了一次对象创建和映射的过程,但在大多数应用场景中,这种开销可以忽略不计。

选择合适的策略

在选择这两种策略时,可以考虑以下因素:

  • 数据模型的通用性:如果 EmployeesRecord 在其他地方也作为数据传输对象,并且在那些场景中需要 department 字段,那么创建专用响应 DTO(策略二)是更好的选择,因为它避免了对原始模型的侵入性修改。
  • API响应的复杂性:如果你的API有多种响应格式,或者对同一个领域对象有不同的字段需求,那么策略二(专用响应 DTO)会提供更高的灵活性和可维护性。
  • 开发速度和简洁性:对于简单的、一次性的需求,或者当 department 字段确实不应出现在任何 JSON 响应中时,@JsonIgnore(策略一)是快速有效的解决方案。
  • 团队规范:遵循团队已有的 DTO 设计和使用规范,选择最符合项目架构风格的方案。

总结

无论是通过 @JsonIgnore 注解还是创建专用响应 DTO 并进行二次映射,这两种方法都能有效地解决在 Java Stream 分组后从 JSON 响应中排除分组字段的问题。@JsonIgnore 提供了简洁快速的解决方案,适用于对原始模型无副作用或副作用可接受的场景;而创建专用 DTO 则提供了更强大的灵活性、更清晰的关注点分离,是构建健壮、可维护 API 的推荐实践。根据具体的项目需求和设计原则,选择最适合你的解决方案,以优化 API 响应并提升应用性能。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

456

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

547

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

335

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1926

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

656

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2395

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

47

2026.01.19

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

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

精品课程

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

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.2万人学习

Java 教程
Java 教程

共578课时 | 81.1万人学习

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

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