Java Streams:将分组结果映射为自定义对象列表

本文介绍如何使用 java stream api 将按字段分组的列表(如 `list`)高效转换为固定结构的自定义对象列表(如 `list`),并安全处理不等长分组(自动补 `null`)。

在实际开发中,常需将扁平数据按某字段(如 value)聚合并展开为结构化对象。例如,给定 PivotMapEgModel 列表,目标是生成 List,其中每个 ResultSet 包含 value 及最多三个 code 字段(code_1、code_2、code_3),不足则补 null。

核心思路分为三步:

  1. 分组聚合:用 Collectors.groupingBy 按 getValue() 分组,并用 Collectors.mapping 提取所有 getCode() 值为 List
  2. 转换条目:对分组结果的 entrySet() 流式遍历,将每个 (key, List) 映射为 ResultSet;
  3. 安全取值:通过辅助方法 getCode(list, index) 防止 IndexOutOfBoundsException,索引越界时返回 null。

以下是完整可运行示例:

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 pivotM

apList = List.of( new PivotMapEgModel(1L, "1"), new PivotMapEgModel(1L, "2"), new PivotMapEgModel(1L, "3"), new PivotMapEgModel(2L, "5") ); 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()); 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 codes, int index) { return index < codes.size() ? codes.get(index) : null; } }

关键注意事项

  • 分组后直接操作 entrySet().stream() 是连接聚合与构造的关键桥梁;
  • 避免在 map() 中硬编码 list.get(i),必须封装边界检查,否则流式处理会因单个异常而中断整个流水线;
  • 若业务允许,也可用 Optional.ofNullable(...).orElse(null) 等方式增强可读性,但本例中自定义 getCode 更简洁高效;
  • 此方案时间复杂度为 O(n),仅一次遍历 + 一次分组后遍历,性能优秀且语义清晰。

该模式适用于任何“分组 → 展开为固定宽表”的场景,是 Java Stream 进阶应用的典型范式。