Java Stream 数据处理笔记:从嵌套集合中过滤特定类别的Map
在Java开发中,我们经常需要处理嵌套集合结构(如List<List<WarehouseDto>>),并从中提取特定类别的数据构建Map。本文将详细讲解如何使用Stream API高效实现这一需求。
一、问题场景描述
假设我们有一个仓库组列表List<WarehouseGroup>,每个仓库组包含多个仓库List<WarehouseDto>。我们需要:
- 将嵌套结构扁平化为单一仓库流
- 过滤出特定类别的仓库(如官方仓
PLATFORM) - 构建以仓库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 // 第三方仓
}
}
六、关键点总结
- 扁平化嵌套结构 :使用
flatMap将List<List<T>>转换为Stream<T> - 过滤条件放置:在收集前进行过滤,避免处理不必要的数据
- 空值安全:多层空值检查防止NPE
- 性能优化 :
- 先过滤后映射
- 大数据量使用并行流
- 使用合适的Map实现(如
ConcurrentHashMap用于并行流)
- 冲突处理:指定合并函数处理键冲突
通过以上方法,您可以高效地从复杂嵌套结构中提取并过滤特定类别的数据,构建所需的Map结构。这种模式在实际项目中非常常见,掌握这些技巧能显著提升代码质量和开发效率。