本文介绍一种高效、简洁的 java stream 方案,通过一次遍历识别重复产品名称,再批量更新 frontname 字段:对同名产品拼接 category,对唯一名称产品仅保留 name。避免嵌套循环,时间复杂度优化至 o(n)。
在实际业务中,我们常需根据字段的“唯一性”对对象进行差异化处理。以 Product 类为例:
@Data
public class Product {
private UUID id;
private String name;
private String categoryName;
private String frontName;
}目标明确:
核心思路是先标记重复项,再统一赋值,避免 Collectors.groupingBy 后二次遍历分组集合,兼顾可读性与性能:
// 第一阶段:识别所有重复的 product name Setseen = new HashSet<>(); Set duplicateNames = productList.stream() .map(Product::getName) .filter(name -> !seen.add(name)) // add() 返回 false → 已存在 → 是重复项 .collect(Collectors.toSet()); // 第二阶段:按规则更新 frontName productList.forEach(product -> { String name = product.getName(); if (duplicateNames.contains(name)) { product.setFrontName(name + "," + product.getCategoryName()); } else { product.setFrontName(name); } });
? 关键技巧说明:HashSet.add() 方法返回 true 表示首次添加成功,false 表示元素已存在。利用这一特性,在 filter 中直接捕获所有“第二次及以后出现”的 name,精准构建 duplicateNames 集合。
.filter(Objects::nonNull) .map(Product::getName)
| 方案 | 时间复杂度 | 是否推荐 | 说明 |
|---|---|---|---|
| 双重 for 循环判断重复 | O(n²) | ❌ | 数据量大时性能急剧下降 |
| groupingBy(name) + counting() 再过滤 | O(n) | △(可读但稍冗余) | 需创建完整分组映射,内存开销略高 |
| 本方案(HashSet.add() 巧用) | O(n) | ✅ | 一次流+一次遍历,零中间集合膨胀,语义清晰 |
该方法已在 Spring Boot 服务中稳定用于商品前台展示逻辑,日均处理万级产品列表无性能瓶颈。建议作为处理“基于字段重复性差异化赋值”类需求的标准实践。