首先需要声明的是,我的开发语言是 PHP,但我对所有语言都懂一点点,然后很多文章,都是看到某个知识点就想写些什么
刚刚再浏览某些文章的时候看到 Java 的流收集器 ( Stream Collectors ),哈哈,瞬间感兴趣,流收集器,光这四个大字看起来就有点高大上的直觉
流收集器 ( Stream Collectors )
众所周知,流 ( Stream
) 是 Java 8 引入的一个新的抽象,让我们可以以声明的方式处理数据。此外,流天生可以利用多核构架,而无需编写单线多线程代码
Collectors
是 Collector
接口的一个实现类,它实现了各种有用的 reduce
操作,例如将元素累积到集合中,根据各种标准汇总元素等
引入命令空间
对了,为了方便演示,我们直接用单个文件来演示,文件名为 MyCollectors.java
MyCollectors.java
import java.util.Arrays; import java.util.List; import java.util.Comparator; import java.util.stream.Collectors;
使用 Collectors 类
为了演示流收集器 Collectors
的用法,我们首先定义一个雇员类 Employee
来保存数据
MyCollectors.java
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; class Employee { private String empId; private String name; private Double salary; private String department; public Employee(String empId, String name, Double salary, String department) { this.empId = empId; this.name = name; this.salary = salary; this.department = department; } public String getEmpId() { return empId; } public void setEmpId(String id ) { empId = id; } public String getName() { return name; } public void setName(String myname ) { name = myname; } public Double getSalary() { return salary; } public void setSalary(double mysalary) { salary = mysalary; } public String getDepartment() { return department; } public void setDepartment(String mydepartment ) { department = mydepartment; } public String toString() { return "Employee(" + empId + "," + name + "," + salary.toString() + "," + department + ")"; } }
然后,我们创建多个 Employee
类的实例,并把它们都放到列表 employees
中
class MyCollectors { public static void main(String[] args) { Employee john = new Employee("E123", "John Nhoj", 200.99, "IT"); Employee south = new Employee("E223", "South Htuos", 299.99, "Sales"); Employee reet = new Employee("E133", "Reet Teer", 300.99, "IT"); Employee prateema = new Employee("E143", "Prateema Rai", 300.99, "Benefits"); Employee yogen = new Employee("E323", "Yogen Rai", 200.99, "Sales"); List<Employee> employees = Arrays.asList(john, south, reet, prateema, yogen); System.out.println(employees); } }
使用命令 javac MyCollectors.java && java MyCollectors
运行,输出结果如下
$ javac MyCollectors.java && java MyCollectors [Employee(E123,John Nhoj,200.99,IT), Employee(E223,South Htuos,299.99,Sales), Employee(E133,Reet Teer,300.99,IT), Employee(E143,Prateema Rai,300.99,Benefits), Employee(E323,Yogen Rai,200.99,Sales)]
好,有了演示数据就好办了,接下来我们使用流收集器来做一些有趣的操作
Collectors.averagingDouble 求取所有雇员薪水的平均数
Double averageSalary = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(averageSalary);
输出结果 260.79
相类似的方法还有
求取 Integer
类型的平均值
public static <T> Collector<T,?,Double> averagingInt(ToIntFunction<? super T> mapper)
求取 Long
类型的平均值
public static <T> Collector<T,?,Double> averagingLong(ToLongFunction<? super T> mapper)
Collectors.summingDouble() 求取所有雇员薪水的总额
Double totalSalary = employees.stream().collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(totalSalary);
输出结果为 1303.95
同样的,相类似的方法还有
求取 Interger
类型的总和
public static <T> Collector<T,?,Integer> summingInt(ToIntFunction<? super T> mapper)
求取 Long
类型的总和
public static <T> Collector<T,?,Long> summingLong(ToLongFunction<? super T> mapper)
查找薪水最大值的雇员
为了查找薪水的最大值,我们就要做以系列的调用了
Double maxSalary = employees.stream().collect(Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)), emp -> emp.get().getSalary())); System.out.println(maxSalary);
输出结果为 300.99
这个调用看起来适不适合很头晕 ? 又长又臭
collectingAndThen()
方法收集收据,使用第二个参数来格式化数据,然后再传递给第一个参数来处理,原型如下
Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)
其中第二个参数 finisher
用于格式化数据,比如我们求取薪水的平均值,并添加美元符号和保留 3 位小数,那么可以使用下面的语句
String avgSalary2 = employees.stream().collect(Collectors.collectingAndThen(Collectors.averagingDouble(Employee::getSalary), new DecimalFormat("$0.000")::format)); System.out.println(avgSalary2);
输出结果为 $260.790
对了,使用 DecimalFormat
需要引入类 java.text.DecimalFormat
一次性统计平均值,总和,最大值,最小值 Collectors.summarizingDouble
我们可以使用 Collectors.summarizingDouble()
函数一次性统计 Double
类型数据的平均值,总和,最大值,最小值
DoubleSummaryStatistics statistics = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println("Average: " + statistics.getAverage() + ", Total: " + statistics.getSum() + ", Max: " + statistics.getMax() + ", Min: "+ statistics.getMin());
输出结果为 Average: 260.79, Total: 1303.95, Max: 300.99, Min: 200.99
Collectors.summarizingDouble()
方法返回的是 DoubleSummaryStatistics
类型的实例,所以需要引入类 java.util.DoubleSummaryStatistics
相类似的方法还有
一次性计算 Integer
类型的统计信息
public static <T> Collector<T,?,IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
一次新计算 Long
类型的统计信息
public static <T> Collector<T,?,LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
结束语
本章节已经有点长了,我们就到此结束吧,贴上以上范例的所有代码
import java.util.Arrays; import java.util.List; import java.util.Comparator; import java.text.DecimalFormat; import java.util.stream.Collectors; import java.util.DoubleSummaryStatistics; class Employee { private String empId; private String name; private Double salary; private String department; public Employee(String empId, String name, Double salary, String department) { this.empId = empId; this.name = name; this.salary = salary; this.department = department; } public String getEmpId() { return empId; } public void setEmpId(String id ) { empId = id; } public String getName() { return name; } public void setName(String myname ) { name = myname; } public Double getSalary() { return salary; } public void setSalary(double mysalary) { salary = mysalary; } public String getDepartment() { return department; } public void setDepartment(String mydepartment ) { department = mydepartment; } public String toString() { return "Employee(" + empId + "," + name + "," + salary.toString() + "," + department + ")"; } } class MyCollectors { public static void main(String[] args) { Employee john = new Employee("E123", "John Nhoj", 200.99, "IT"); Employee south = new Employee("E223", "South Htuos", 299.99, "Sales"); Employee reet = new Employee("E133", "Reet Teer", 300.99, "IT"); Employee prateema = new Employee("E143", "Prateema Rai", 300.99, "Benefits"); Employee yogen = new Employee("E323", "Yogen Rai", 200.99, "Sales"); List<Employee> employees = Arrays.asList(john, south, reet, prateema, yogen); System.out.println(employees); Double averageSalary = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(averageSalary); Double totalSalary = employees.stream().collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(totalSalary); Double maxSalary = employees.stream().collect(Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)), emp -> emp.get().getSalary())); System.out.println(maxSalary); String avgSalary2 = employees.stream() .collect(Collectors.collectingAndThen(Collectors.averagingDouble(Employee::getSalary), new DecimalFormat("$0.000")::format)); System.out.println(avgSalary2); DoubleSummaryStatistics statistics = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println("Average: " + statistics.getAverage() + ", Total: " + statistics.getSum() + ", Max: " + statistics.getMax() + ", Min: "+ statistics.getMin()); } }