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结构。这种模式在实际项目中非常常见,掌握这些技巧能显著提升代码质量和开发效率。

相关推荐
tingshuo29173 小时前
S001 【模板】从前缀函数到KMP应用 字符串匹配 字符串周期
笔记
怒放吧德德5 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆7 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
心之语歌9 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊11 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang11 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang12 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解12 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
阿白的白日梦16 小时前
winget基础管理---更新/修改源为国内源
windows
SimonKing16 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员