是否可以仅使用 reduce 函数将 Java Stream<T> 缩减为新的 Stream<T>

Is it possible to reduce a Java Stream<T> to a new Stream<T> solely with the reduce function

我正在尝试通过删除基于特定属性的重复项并增加这些属性的值,将对象流减少为相同对象类型的新流。在下面的动物示例中,我将匹配 typeOfAnimal,然后繁殖并对新动物的年龄求和。所以列表:

[
  {"typeOfAnimal": "dog", "breed": "Labrador", "age": 5},
  {"typeOfAnimal": "dog", "breed": "Labrador", "age": 3},
  {"typeOfAnimal": "dog", "breed": "Poodle", "age": 7},
  {"typeOfAnimal": "cat", "breed": "Bengal", "age": 1}
]

结果应如下所示:

[
  {"typeOfAnimal": "dog", "breed": "Labrador", "age": 8},
  {"typeOfAnimal": "dog", "breed": "Poodle", "age": 7},
  {"typeOfAnimal": "cat", "breed": "Bengal", "age": 1}
]

到目前为止,为了实现这个结果,我不得不使用 groupingByreducing 收集器,因为我无法将其写为单个 reducer 运算符。这是我的工作示例:

Stream<Animal> results = animals
    .stream()
    .collect(
        groupingBy(Animal::getTypeOfAnimal,
            groupingBy(Animal::getBreed,
                reducing(
                    new Animal().withAge(0),
                    (a,c) -> new Animal()
                        .withTypeOfAnimal(c.getTypeOfAnimal())
                        .withBreed(c.getBreed())
                        .withAge(c.getAge() + a.getAge())))))
    .values()
    .stream()
    .flatMap(a -> a.values().stream());

reduce 运算符是否允许这样做,或者我是否需要坚持使用当前示例?我偏爱单个 reducer 函数是因为我的实际代码具有更多级别,因此有更多 groupingBy 语句

那么,您现在每次都按一个 属性 分组。

但您也可以立即按所需属性分组:

首先,创建一条GroupingKey记录:

public static record GroupingKey(String type, String breed) {
    public static GroupingKey of(Animal animal) {
        return new GroupingKey(animal.getTypeOfAnimal(), animal.getBreed());
    }
}

这有助于我们定义动物在哪些领域进行分组。

然后我们定义一个merge方法,它有助于合并两个动物。

private static Animal merge(Animal a, Animal b) {
    int age = (a != null ? a.getAge() : 0);
    return new Animal(b.getTypeOfAnimal(), b.getBreed(), age + b.getAge());
}

然后你可以减少一次:

Map<GroupingKey, Animal> map = animals.stream()
    .collect(groupingBy(GroupingKey::of, reducing(null, t -> merge(t))));

然后通过调用 values(),您可以检索包含所有 AnimalCollection