仅使用reduce函数能否将Java Stream<T>归约为同类型的新Stream<T>
实现方案
完全可以用单个reduce运算符实现,不需要嵌套多层groupingBy,特别适合匹配层级多的场景,代码结构不会随匹配字段增加变复杂。
核心思路
用Map作为reduce的中间容器,key是你需要匹配的所有属性的组合,value是累加后的Animal对象,每次处理元素时直接合并对应key的age值,最后提取Map的values即可。
代码示例
Java 16+ 版本(推荐,用Record做组合键,避免哈希冲突)
先定义组合键,把所有需要匹配的字段都放进去,后续新增匹配字段只需要修改这个Record即可:
// 组合键:所有需要匹配去重的字段 record AnimalKey(String typeOfAnimal, String breed) {} Stream<Animal> results = animals.stream() .reduce( // 初始容器:空HashMap new HashMap<AnimalKey, Animal>(), // 单元素累加逻辑 (accMap, currentAnimal) -> { AnimalKey key = new AnimalKey(currentAnimal.getTypeOfAnimal(), currentAnimal.getBreed()); accMap.merge( key, currentAnimal, (existed, newVal) -> new Animal() .withTypeOfAnimal(existed.getTypeOfAnimal()) .withBreed(existed.getBreed()) .withAge(existed.getAge() + newVal.getAge()) ); return accMap; }, // 并行流场景下的容器合并逻辑 (leftMap, rightMap) -> { rightMap.forEach((key, val) -> leftMap.merge( key, val, (existed, newVal) -> new Animal() .withTypeOfAnimal(existed.getTypeOfAnimal()) .withBreed(existed.getBreed()) .withAge(existed.getAge() + newVal.getAge()) ) ); return leftMap; } ) .values() .stream();
低版本Java兼容方案
没有Record的情况下可以用List.of()当组合键,List的equals和hashCode默认按元素匹配,也能实现效果:
Stream<Animal> results = animals.stream() .reduce( new HashMap<List<String>, Animal>(), (accMap, currentAnimal) -> { List<String> key = List.of(currentAnimal.getTypeOfAnimal(), currentAnimal.getBreed()); accMap.merge( key, currentAnimal, (existed, newVal) -> new Animal() .withTypeOfAnimal(existed.getTypeOfAnimal()) .withBreed(existed.getBreed()) .withAge(existed.getAge() + newVal.getAge()) ); return accMap; }, (leftMap, rightMap) -> { rightMap.forEach((key, val) -> leftMap.merge( key, val, (existed, newVal) -> new Animal() .withTypeOfAnimal(existed.getTypeOfAnimal()) .withBreed(existed.getBreed()) .withAge(existed.getAge() + newVal.getAge()) ) ); return leftMap; } ) .values() .stream();
优势说明
- 不需要嵌套多层
groupingBy,后续新增匹配维度只需要给组合键加字段即可,代码结构完全不变 - 逻辑更内聚,所有累加规则都在merge函数里,修改更方便
- 同时兼容串行和并行流场景
内容的提问来源于stack exchange,提问作者APW
相关产品推荐
相关产品推荐

