如何基于Condition列表对Promotion对象分组(Java 8 Collectors.groupingBy)
用Java 8 Collectors.groupingBy实现按Condition列表内容分组(第三方类不可修改)
完全可以实现,核心思路是为Collectors.groupingBy提供基于Condition列表内容的键提取逻辑,而非直接使用Criteria对象作为分组键。因为第三方类可能未正确实现equals()和hashCode(),我们需要自行构建能唯一标识Condition列表内容的分组键。
实现步骤
确定Condition的内容标识方式:
- 如果第三方
Condition类已经基于属性内容实现了正确的equals()和hashCode(),直接用其列表作为键即可。 - 如果
Condition的equals()/hashCode()是基于对象引用(而非内容),则需要提取Condition的所有关键属性,封装成自定义的键对象(或属性列表)来实现内容比对。
- 如果第三方
编写键提取函数:
针对不同的Condition实现情况,编写对应的函数从Promotion中提取分组键。执行分组:
将键提取函数传入Collectors.groupingBy()完成分组。
代码示例
场景1:Condition已正确实现equals/hashCode
假设Condition类的equals()和hashCode()会比较属性内容,直接用Condition列表作为分组键:
// 定义键提取器:从Promotion中获取Condition列表 Function<Promotion, List<Condition>> groupingKey = promo -> new ArrayList<>(promo.getCriteria().getConditions()); // 用ArrayList保证可序列化,或用ImmutableList.copyOf() // 执行分组 Map<List<Condition>, List<Promotion>> groupedPromos = promotions.stream() .collect(Collectors.groupingBy(groupingKey));
场景2:Condition未正确实现equals/hashCode
此时需要自定义键对象,提取Condition的关键属性来实现内容比对:
// 自定义键类,基于Condition的属性实现equals和hashCode class ConditionContentKey { private final String conditionType; private final int threshold; // 从Condition对象提取属性初始化 public ConditionContentKey(Condition cond) { this.conditionType = cond.getType(); this.threshold = cond.getThreshold(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConditionContentKey that = (ConditionContentKey) o; return threshold == that.threshold && Objects.equals(conditionType, that.conditionType); } @Override public int hashCode() { return Objects.hash(conditionType, threshold); } } // 键提取器:将Condition列表转换为自定义键列表 Function<Promotion, List<ConditionContentKey>> groupingKey = promo -> promo.getCriteria().getConditions().stream() .map(ConditionContentKey::new) .collect(Collectors.toList()); // 执行分组 Map<List<ConditionContentKey>, List<Promotion>> groupedPromos = promotions.stream() .collect(Collectors.groupingBy(groupingKey));
场景3:Condition列表顺序不影响分组
如果[condA, condB]和[condB, condA]需要归为同一组,需先对键列表排序:
Function<Promotion, List<ConditionContentKey>> sortedGroupingKey = promo -> promo.getCriteria().getConditions().stream() .map(ConditionContentKey::new) .sorted(Comparator.comparing(ConditionContentKey::getConditionType) .thenComparingInt(ConditionContentKey::getThreshold)) .collect(Collectors.toList()); Map<List<ConditionContentKey>, List<Promotion>> groupedPromos = promotions.stream() .collect(Collectors.groupingBy(sortedGroupingKey));
验证预期结果
按照上述代码,你的测试场景会得到预期分组:
- Grp1:promo1、promo3(Condition列表内容一致)
- Grp2:promo2、promo4(Condition列表内容一致)
- Grp3:promo5(Condition列表唯一)
内容的提问来源于stack exchange,提问作者net user
相关产品推荐
相关产品推荐

