首先需要声明的是,我的开发语言是 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 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 Collector averagingInt(ToIntFunction super T> mapper)
求取 Long 类型的平均值
public static Collector 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 Collector summingInt(ToIntFunction super T> mapper)
求取 Long 类型的总和
public static Collector 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 collectingAndThen(Collector downstream, Function 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 Collector summarizingInt(ToIntFunction super T> mapper)
一次新计算 Long 类型的统计信息
public static Collector 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 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());
}
}