Java Stream 数据处理笔记:从嵌套集合中过滤特定类别的Map

Java Stream 数据处理笔记:从嵌套集合中过滤特定类别的Map

在Java开发中,我们经常需要处理嵌套集合结构(如List<List<WarehouseDto>>),并从中提取特定类别的数据构建Map。本文将详细讲解如何使用Stream API高效实现这一需求。

一、问题场景描述

假设我们有一个仓库组列表List<WarehouseGroup>,每个仓库组包含多个仓库List<WarehouseDto>。我们需要:

  1. 将嵌套结构扁平化为单一仓库流
  2. 过滤出特定类别的仓库(如官方仓PLATFORM
  3. 构建以仓库ID为键、仓库对象为值的Map
java 复制代码
// 原始数据结构
class WarehouseGroup {
    private List<WarehouseDto> warehouses;
    // getter/setter
}

class WarehouseDto {
    private Long id;
    private WarehouseCategory category;
    // getter/setter
}

enum WarehouseCategory {
    PLATFORM,   // 官方仓
    THIRD_PARTY // 第三方仓
}

二、基础实现:无过滤的Map构建

首先实现基本功能,不添加过滤条件:

java 复制代码
Map<Long, WarehouseDto> warehouseMap = warehouseGroupList.stream()
    .map(WarehouseGroup::getWarehouses)  // 转换为List<WarehouseDto>的流
    .flatMap(List::stream)               // 扁平化为WarehouseDto流
    .collect(Collectors.toMap(
        WarehouseDto::getId,             // 键:仓库ID
        Function.identity(),             // 值:仓库对象本身
        (existing, replacement) -> existing, // 冲突处理:保留已有值
        LinkedHashMap::new               // Map实现:保持插入顺序
    ));

三、添加过滤条件:只保留官方仓

在构建Map前添加过滤条件,只保留PLATFORM类别的仓库:

java 复制代码
Map<Long, WarehouseDto> platformWarehouseMap = warehouseGroupList.stream()
    .map(WarehouseGroup::getWarehouses)
    .flatMap(List::stream)
    // 关键过滤步骤:只保留官方仓
    .filter(warehouse -> WarehouseCategory.PLATFORM.equals(warehouse.getCategory()))
    .collect(Collectors.toMap(
        WarehouseDto::getId,
        Function.identity(),
        (existing, replacement) -> existing,
        LinkedHashMap::new
    ));

四、最佳实践与优化技巧

1. 空值安全处理

避免空指针异常,添加多层空值检查:

java 复制代码
Map<Long, WarehouseDto> safePlatformMap = warehouseGroupList.stream()
    .filter(Objects::nonNull) // 过滤null的WarehouseGroup
    .map(WarehouseGroup::getWarehouses)
    .filter(Objects::nonNull) // 过滤null的warehouses列表
    .flatMap(List::stream)
    .filter(Objects::nonNull) // 过滤null的WarehouseDto
    .filter(warehouse -> WarehouseCategory.PLATFORM.equals(
        Optional.ofNullable(warehouse.getCategory()).orElse(null)
    ))
    .collect(Collectors.toMap(...));

2. 性能优化:先过滤后映射

遵循"先过滤,后映射"原则,减少不必要的计算:

java 复制代码
// 优化版:先过滤出官方仓,再提取ID
Map<Long, WarehouseDto> optimizedMap = warehouseGroupList.stream()
    .map(WarehouseGroup::getWarehouses)
    .flatMap(List::stream)
    .filter(warehouse -> 
        warehouse != null && 
        WarehouseCategory.PLATFORM.equals(warehouse.getCategory())
    )
    .collect(Collectors.toMap(WarehouseDto::getId, Function.identity()));

3. 并行处理大数据量

当数据量较大时,使用并行流提升性能:

java 复制代码
Map<Long, WarehouseDto> parallelMap = warehouseGroupList.parallelStream()
    .map(WarehouseGroup::getWarehouses)
    .flatMap(List::stream)
    .filter(warehouse -> WarehouseCategory.PLATFORM.equals(warehouse.getCategory()))
    .collect(Collectors.toConcurrentMap( // 使用线程安全的ConcurrentHashMap
        WarehouseDto::getId,
        Function.identity(),
        (existing, replacement) -> existing
    ));

五、完整代码示例

java 复制代码
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class WarehouseStreamDemo {

    public Map<Long, WarehouseDto> createPlatformWarehouseMap(
        List<WarehouseGroup> warehouseGroupList
    ) {
        return warehouseGroupList.stream()
            .filter(Objects::nonNull)
            .map(WarehouseGroup::getWarehouses)
            .filter(Objects::nonNull)
            .flatMap(List::stream)
            .filter(Objects::nonNull)
            .filter(warehouse -> 
                WarehouseCategory.PLATFORM.equals(
                    Optional.ofNullable(warehouse.getCategory()).orElse(null)
                )
            )
            .collect(Collectors.toMap(
                WarehouseDto::getId,
                Function.identity(),
                (existing, replacement) -> existing,
                LinkedHashMap::new
            ));
    }
    
    // 实体类定义
    static class WarehouseGroup {
        private List<WarehouseDto> warehouses;
        public List<WarehouseDto> getWarehouses() { return warehouses; }
    }
    
    static class WarehouseDto {
        private Long id;
        private WarehouseCategory category;
        public Long getId() { return id; }
        public WarehouseCategory getCategory() { return category; }
    }
    
    enum WarehouseCategory {
        PLATFORM,   // 官方仓
        THIRD_PARTY // 第三方仓
    }
}

六、关键点总结

  1. 扁平化嵌套结构 :使用flatMapList<List<T>>转换为Stream<T>
  2. 过滤条件放置:在收集前进行过滤,避免处理不必要的数据
  3. 空值安全:多层空值检查防止NPE
  4. 性能优化
    • 先过滤后映射
    • 大数据量使用并行流
    • 使用合适的Map实现(如ConcurrentHashMap用于并行流)
  5. 冲突处理:指定合并函数处理键冲突

通过以上方法,您可以高效地从复杂嵌套结构中提取并过滤特定类别的数据,构建所需的Map结构。这种模式在实际项目中非常常见,掌握这些技巧能显著提升代码质量和开发效率。

相关推荐
腻害兔2 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社3 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
克里斯蒂亚诺更新3 小时前
ruoyi角色权限的对应关系
笔记
萧瑟余晖4 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a1117766 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
维天说7 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
破碎的南瓜7 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
Zane19948 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
你想知道什么?8 小时前
线性回归-学习笔记
笔记·学习·线性回归