导读:本期聚焦于小伙伴创作的《在Java中如何使用Collectors.reducing实现归约操作》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《在Java中如何使用Collectors.reducing实现归约操作》有用,将其分享出去将是对创作者最好的鼓励。

在Java的Stream API中,归约操作是将集合中的多个元素经过计算合并为单个结果的过程,Collectors.reducing是专门用于实现这类操作的收集器,它提供了三种重载形式,可以适配不同的归约需求,比如数值计算、对象属性合并、自定义规则聚合等场景。

在Java中如何使用Collectors.reducing实现归约操作

Collectors.reducing的核心重载形式

Collectors.reducing共有三个重载方法,分别对应不同的使用场景,开发者可以根据实际需求选择合适的版本。

1. 单参数形式:reducing(BinaryOperator<T> op)

这种形式接收一个二元操作符,会将流中的元素依次两两合并,最终得到一个Optional<T>类型的结果,适用于不需要初始值、直接对流中所有元素进行归约的场景。

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class ReducingDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        // 求和归约,不需要初始值
        Optional<Integer> sumOptional = numbers.stream()
                .collect(Collectors.reducing((a, b) -> a + b));
        // 输出结果:15
        sumOptional.ifPresent(System.out::println);
    }
}

2. 双参数形式:reducing(T identity, BinaryOperator<T> op)

这种形式除了二元操作符之外,还接收一个初始值identity,当流为空时会直接返回这个初始值,返回结果是T类型而非Optional,适合需要明确默认值的场景。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ReducingDemo2 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        // 求和,初始值为0,流为空时返回0
        Integer sum = numbers.stream()
                .collect(Collectors.reducing(0, (a, b) -> a + b));
        // 输出结果:15
        System.out.println(sum);

        List<Integer> emptyList = Arrays.asList();
        Integer emptySum = emptyList.stream()
                .collect(Collectors.reducing(0, (a, b) -> a + b));
        // 输出结果:0
        System.out.println(emptySum);
    }
}

3. 三参数形式:reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op)

这种形式增加了映射函数mapper,会在归约前先将流中的元素转换为指定类型,再进行归约操作,适合需要对元素先处理再聚合的场景,比如对象集合中提取某个属性再计算。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }
}

public class ReducingDemo3 {
    public static void main(String[] args) {
        List<User> userList = Arrays.asList(
                new User("张三", 20),
                new User("李四", 25),
                new User("王五", 22)
        );
        // 先提取年龄,再求和,初始值为0
        Integer totalAge = userList.stream()
                .collect(Collectors.reducing(
                        0,                  // 初始值
                        User::getAge,       // 映射函数,提取年龄
                        (a, b) -> a + b     // 归约规则,求和
                ));
        // 输出结果:67
        System.out.println(totalAge);
    }
}

Collectors.reducing的使用注意事项

  • 归约操作需要满足结合律,否则多线程并行流下执行结果会和预期不一致,比如减法操作就不符合结合律,不建议使用reducing做减法归约。
  • 单参数形式的reducing在流为空时会返回Optional.empty(),使用时需要做空值判断,避免空指针异常。
  • 三参数形式的映射函数如果返回null,会导致归约过程出现异常,需要确保映射逻辑不会返回null值。

与其他归约方法的对比

Stream API中除了Collectors.reducing,还有Stream.reduce()方法也可以实现归约,两者的核心逻辑一致,但是使用场景略有不同:

对比项Collectors.reducingStream.reduce()
适用场景作为收集器用在collect()方法中,适合和其他收集器组合使用直接用在Stream流上,适合单独的归约操作
返回值单参数返回Optional,双/三参数返回具体类型单参数返回Optional,双/三参数返回具体类型
组合性可以方便地和groupingBy等收集器组合实现分组归约不支持直接和其他收集器组合

如果需要先对集合分组再对每组做归约,使用Collectors.reducing配合Collectors.groupingBy会更简洁:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Product {
    private String category;
    private Double price;

    public Product(String category, Double price) {
        this.category = category;
        this.price = price;
    }

    public String getCategory() {
        return category;
    }

    public Double getPrice() {
        return price;
    }
}

public class ReducingDemo4 {
    public static void main(String[] args) {
        List<Product> productList = Arrays.asList(
                new Product("电子", 1999.0),
                new Product("电子", 2999.0),
                new Product("图书", 59.0),
                new Product("图书", 89.0)
        );
        // 按分类分组,计算每类商品的总价
        Map<String, Double> categoryTotalPrice = productList.stream()
                .collect(Collectors.groupingBy(
                        Product::getCategory,
                        Collectors.reducing(
                                0.0,
                                Product::getPrice,
                                (a, b) -> a + b
                        )
                ));
        // 输出结果:{电子=4998.0, 图书=148.0}
        System.out.println(categoryTotalPrice);
    }
}
实际开发中,如果是简单的数值归约,比如求和、求最大值,也可以直接使用Collectors.summingInt、Collectors.maxBy等专用收集器,代码可读性会更高,reducing更适合自定义归约规则的场景。

Collectors.reducingJava集合归约Stream_API修改时间:2026-07-19 03:36:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。