17370845950

如何高效地为重复与唯一名称的产品设置不同的 frontName

本文介绍一种高效、简洁的 java stream 方案,用于批量处理产品列表:对名称重复的产品拼接 category 名称生成 frontname,对唯一名称产品则直接赋值 name。

在实际业务中,我们常需根据字段的重复性对对象进行差异化处理。以 Product 类为例,当多个产品具有相同 name(但属于不同 categoryName)时,需将 frontName 设为 "name,categoryName";而名称唯一的商品,则仅设为 name。核心挑战在于:一次遍历识别重复项,再二次遍历完成赋值,避免嵌套循环导致 O(n²) 时间复杂度。

以下是一个兼顾可读性与性能的解决方案:

// 第一步:识别所有重复的 product name
Set seen = 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。

该方法简洁、高效、易于维护,是处理此类“分组差异化赋值”场景的推荐实践。