
本文详解如何使用 java stream api 将按字段分组的原始列表(如 `list
在 Java 8+ 的函数式编程实践中,将扁平数据流聚合为结构化业务对象是常见需求。以本例为例:我们有一组 PivotMapEgModel 对象,需按 value 分组,并将每组最多 3 个 code 值分别填入 ResultSet 的 code_1、code_2、code_3 字段(不足则补 null)。关键在于避免显式 for 循环或临时 Map 遍历,全程使用 Stream 管道完成。
核心思路分为三步:
-
分组并提取值:用 Collectors.groupingBy(key, Collectors.mapping(valueMapper, toList())) 构建 Map
>; -
转为流式条目:调用 entrySet().stream() 将 Map 转为 Stream
>>; - 构造目标对象:对每个 Entry,安全取索引 0/1/2 的 code 值(越界返回 null),实例化 ResultSet。
以下是完整可运行代码示例:
// 辅助方法:安全获取 List 中指定索引的元素(越界返回 null) private static String getCode(Listcodes, int index) { return index < codes.size() ? codes.get(index) : null; } // 主转换逻辑 List result = pivotMapList.stream() .collect(Collectors.groupingBy( PivotMapEgModel::getValue, Collectors.mapping(PivotMapEgModel::getCode, Collectors.toList()) )) .entrySet() .stream() .map(entry -> new ResultSet( entry.getKey(), getCode(entry.getValue(), 0), getCode(entry.getValue(), 1), getCode(entry.getValue(), 2) )) .collect(Collectors.toList());
✅ 注意事项:
立即学习“Java免费学习笔记(深入)”;
- getCode() 方法必不可少——直接调用 list.get(1) 在列表长度不足时会抛 IndexOutOfBoundsException;
- 若 ResultSet 类未提供全参构造器(如使用 Lombok @AllArgsConstructor),请确保字段顺序与构造器参数严格一致;
- 如需保持原始分组顺序(如按 value 升序),可在最后添加 .sorted(Comparator.comparingLong(ResultSet::getValue));
- 性能上,该方案仅遍历原始列表 1 次(分组阶段)+ Entry 集合 1 次(映射阶段),时间复杂度 O(n),优于嵌套循环。
最终输出即为预期的 List
[ResultSet(value=1, code_1="1", code_2="2", code_3="3"), ResultSet(value=2, code_1="5", code_2=null, code_3=null)]
此模式可轻松扩展至更多字段(如 code_4, code_5),只需调整 getCode() 调用次数及 ResultSet 结构即可,充分体现 Stream API 的简洁性与可维护性。










