Java函数式编程:如何用三参数collect方法计算员工薪资总和
如何使用并行流的
collect(supplier, accumulator, combiner)计算员工薪资总和? 嗨,作为Java函数式编程的新手,搞清楚这个三参数的collect方法确实很重要,尤其是在并行流场景下。咱们先拆解这三个参数的作用,再把你的薪资求和方法补全,让你能直观看到它的用法。
三个参数的核心作用
先把每个参数的职责说清楚,这是理解并行流中collect工作原理的关键:
- Supplier(供应者):负责创建一个独立的容器,用来存储每个线程的中间计算结果。因为并行流会把数据拆分给多个线程处理,每个线程都需要自己的容器,所以supplier必须能返回新的实例。
- Accumulator(累加器):一个
BiConsumer函数,负责把单个元素的数值(这里是员工薪资)添加到当前线程的容器中。 - Combiner(合并器):当各个线程的局部计算完成后,combiner负责把多个线程的容器结果合并成最终的总结果。这一步是并行流特有的,串行流不会用到它。
补全你的薪资求和方法
针对你的需求,我们可以用两种常见的容器实现:一种是用float[](利用数组的引用特性实现可变容器),另一种是用AtomicFloat(线程安全的浮点型容器)。下面给出完整的可运行代码:
完整代码示例
首先补上Employee类(你的代码里没包含,不然编译通不过):
class Employee { private int id; private String name; private int age; private String role; private float salary; public Employee(int id, String name, int age, String role, float salary) { this.id = id; this.name = name; this.age = age; this.role = role; this.salary = salary; } public float getSalary() { return salary; } public int getAge() { return age; } }
然后补全sumOfSalaryOfAllEmployees方法,这里用float[]作为容器(相比AtomicFloat更轻量):
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class SumMethodsOfCollectorclass { public static void main(String[] args) { List<Employee> list = new ArrayList<>(); list.add(new Employee(6, "Nick", 27, "Software Engineer", 44000f)); list.add(new Employee(9, "Tom", 23, "Civil Engineer", 32000f)); list.add(new Employee(3, "Jon", 29, "Mechanical Engineer", 37000f)); list.add(new Employee(4, "Harry", 21, "Surgeon", 55000f)); list.add(new Employee(8, "Don", 25, "Laywer", 50000f)); list.add(new Employee(7, "Marry", 20, "Police", 29000f)); list.add(new Employee(2, "Angel", 22, "Professor", 35000f)); list.add(new Employee(1, "Kate", 23, "Teacher", 29000f)); list.add(new Employee(5, "Evan", 22, "Pilot", 44000f)); sumOfAgeOfAllEmployees(list); sumOfSalaryOfAllEmployees(list); } private static void sumOfAgeOfAllEmployees(List<Employee> list) { Integer result = list.stream().parallel().collect(Collectors.summingInt(i -> i.getAge())); System.out.println("The sum of age of all employees - " + result); } private static void sumOfSalaryOfAllEmployees(List<Employee> list) { // 使用三参数collect计算薪资总和 float totalSalary = list.parallelStream().collect( // Supplier: 每个线程创建一个新的float数组,初始值为0 () -> new float[1], // Accumulator: 把当前员工的薪资加到线程本地的数组里 (salaryArr, employee) -> salaryArr[0] += employee.getSalary(), // Combiner: 把两个线程的数组结果合并,把第二个数组的值加到第一个里 (arr1, arr2) -> arr1[0] += arr2[0] )[0]; // 最后取出数组里的总数值 System.out.println("The sum of salary of all employees - " + totalSalary); } }
代码解释
- Supplier:
() -> new float[1]——每个线程都得到一个新的float数组,初始值是0,用来存储该线程处理的员工薪资之和。 - Accumulator:
(salaryArr, employee) -> salaryArr[0] += employee.getSalary()——遍历每个员工,把薪资累加到当前线程的数组元素中。 - Combiner:
(arr1, arr2) -> arr1[0] += arr2[0]——当多个线程完成局部计算后,把第二个线程的总和加到第一个线程的总和里,最终合并成全局总和。
用AtomicFloat的实现方式(线程安全容器)
如果你想更明确地处理线程安全,也可以用AtomicFloat:
import java.util.concurrent.atomic.AtomicFloat; private static void sumOfSalaryOfAllEmployees(List<Employee> list) { float totalSalary = list.parallelStream().collect( () -> new AtomicFloat(0f), (atomicFloat, employee) -> atomicFloat.addAndGet(employee.getSalary()), (af1, af2) -> af1.addAndGet(af2.get()) ).get(); System.out.println("The sum of salary of all employees - " + totalSalary); }
为什么不用Collectors.summingFloat?
你已经用Collectors.summingInt计算了年龄,其实薪资求和也可以用Collectors.summingFloat(),代码会更简洁:
float totalSalary = list.parallelStream().collect(Collectors.summingFloat(Employee::getSalary));
但手动实现三参数的collect能让你更清楚并行流背后的工作机制——拆分任务、局部累加、合并结果,这对理解函数式编程的底层逻辑很有帮助。
内容的提问来源于stack exchange,提问作者user14383344
相关产品推荐
相关产品推荐

