
本文介绍一种高效、简洁的 java stream 方案,用于批量处理产品列表:对名称重复的产品拼接 category 名称生成 frontname,对唯一名称产品则直接赋值 name。
在实际业务中,我们常需根据字段的重复性对对象进行差异化处理。以 Product 类为例,当多个产品具有相同 name(但属于不同 categoryName)时,需将 frontName 设为 "name,categoryName";而名称唯一的商品,则仅设为 name。核心挑战在于:一次遍历识别重复项,再二次遍历完成赋值,避免嵌套循环导致 O(n²) 时间复杂度。
以下是一个兼顾可读性与性能的解决方案:
// 第一步:识别所有重复的 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); } });
✅ 关键点说明:
- seen.add(name) 利用 HashSet.add() 的返回值(true 表示新增成功,false 表示已存在),精准捕获首次出现后的所有重复 name;
- 使用 Set
存储重复名,保证后续 contains() 查询为 O(1); - 整体时间复杂度为 O(n),空间复杂度为 O(n)(最坏情况所有 name 均不同);
- 无需修改原始类或引入第三方库,纯 JDK 8+ Stream 实现。
⚠️ 注意事项:
- 此方案会原地修改 productList 中的对象,若需不可变处理,请先 stream().map(...).collect(...) 构建新列表;
- 若 name 可能为 null,建议提前过滤或使用 Objects.toString(p.getName(), "") 避免 NPE;
- 如需区分“严格重复”(至少出现两次)而非“第二次及以后”,当前逻辑已满足——duplicateNames 中只含真正重复的 name。
该方法简洁、高效、易于维护,是处理此类“分组差异化赋值”场景的推荐实践。










