如何使用Java Streams按id分组合并多行数据为单行?
解决方案
核心思路
通过Java Stream的Collectors.toMap()方法实现按id分组,同时自定义合并逻辑,将同一id下多个pMap对象的非空字段整合到一个对象中。
代码实现
假设你已经有了List<pMap>类型的数据源,以下是完整实现代码:
1. 实体类与样本数据
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import lombok.Data; // 你的实体类(Java类名建议首字母大写,这里沿用你的命名) @Data class pMap { long id; String rating; String movieName; // 无参、全参构造器 public pMap() {} public pMap(long id, String rating, String movieName) { this.id = id; this.rating = rating; this.movieName = movieName; } } public class MergeDemo { public static void main(String[] args) { // 模拟从数据库获取的样本数据 List<pMap> pMapList = Arrays.asList( new pMap(1, "PG-13", ""), new pMap(1, "", "Avatar"), new pMap(2, "", "Avatar 2"), new pMap(2, "PG", "") );
2. Stream分组合并逻辑
// 按id分组并合并字段 Map<Long, pMap> mergedMap = pMapList.stream() .collect(Collectors.toMap( pMap::getId, // 以id作为Map的键 Function.identity(), // 初始值为当前pMap对象 (existing, newItem) -> { // 键重复时的合并逻辑 pMap merged = new pMap(); merged.setId(existing.getId()); // 合并rating:优先取已有对象的非空值,为空则用新对象的 merged.setRating(isNotEmpty(existing.getRating()) ? existing.getRating() : newItem.getRating()); // 合并movieName:逻辑同上 merged.setMovieName(isNotEmpty(existing.getMovieName()) ? existing.getMovieName() : newItem.getMovieName()); // 其他8个字段按此逻辑逐一处理即可 return merged; } )); // 打印验证结果 mergedMap.forEach((id, pmap) -> System.out.println(id + "=" + pmap)); } // 自定义非空判断工具(无需依赖第三方库) private static boolean isNotEmpty(String str) { return str != null && !str.trim().isEmpty(); } }
关键说明
Collectors.toMap()的第三个参数是核心:当同一id对应多个pMap时,该函数负责合并两个对象的字段。- 针对10个字段,只需重复
isNotEmpty()的判断逻辑,优先保留非空值即可。 - 如果业务允许同一字段存在多个非空值(比如同一id有不同rating),可按需调整合并规则(如取最后一个值、拼接字符串等)。
内容的提问来源于stack exchange,提问作者Vamsi
相关产品推荐
相关产品推荐

