
本文介绍如何使用 java stream api 将按字段分组的列表(如 `list
在实际开发中,常需将扁平数据按某字段(如 value)聚合并展开为结构化对象。例如,给定 PivotMapEgModel 列表,目标是生成 List<ResultSet>,其中每个 ResultSet 包含 value 及最多三个 code 字段(code_1、code_2、code_3),不足则补 null。
核心思路分为三步:
- 分组聚合:用 Collectors.groupingBy 按 getValue() 分组,并用 Collectors.mapping 提取所有 getCode() 值为 List<String>;
- 转换条目:对分组结果的 entrySet() 流式遍历,将每个 (key, List<String>) 映射为 ResultSet;
- 安全取值:通过辅助方法 getCode(list, index) 防止 IndexOutOfBoundsException,索引越界时返回 null。
以下是完整可运行示例:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
import java.util.*;
import java.util.stream.Collectors;
@Data
@AllArgsConstructor
class ResultSet {
long value;
String code_1;
String code_2;
String code_3;
}
class PivotMapEgModel {
private final long value;
private final String code;
PivotMapEgModel(long value, String code) {
this.value = value;
this.code = code;
}
long getValue() { return value; }
String getCode() { return code; }
}
// 主逻辑
public class StreamToCustomObject {
public static void main(String[] args) {
List<PivotMapEgModel> pivotMapList = List.of(
new PivotMapEgModel(1L, "1"),
new PivotMapEgModel(1L, "2"),
new PivotMapEgModel(1L, "3"),
new PivotMapEgModel(2L, "5")
);
List<ResultSet> 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());
System.out.println(result);
// 输出: [ResultSet(value=1, code_1=1, code_2=2, code_3=3),
// ResultSet(value=2, code_1=5, code_2=null, code_3=null)]
}
private static String getCode(List<String> codes, int index) {
return index < codes.size() ? codes.get(index) : null;
}
}✅ 关键注意事项:
立即学习“Java免费学习笔记(深入)”;
- 分组后直接操作 entrySet().stream() 是连接聚合与构造的关键桥梁;
- 避免在 map() 中硬编码 list.get(i),必须封装边界检查,否则流式处理会因单个异常而中断整个流水线;
- 若业务允许,也可用 Optional.ofNullable(...).orElse(null) 等方式增强可读性,但本例中自定义 getCode 更简洁高效;
- 此方案时间复杂度为 O(n),仅一次遍历 + 一次分组后遍历,性能优秀且语义清晰。
该模式适用于任何“分组 → 展开为固定宽表”的场景,是 Java Stream 进阶应用的典型范式。

















