你可能很疑惑,我们在刚刚的章节 Java 流收集器 ( Stream Collectors ) ( 三 ) - 分组元素 ( grouping ) 学习了分组,怎么又来一个划片,分组和划片不就是一个意思么?
我原来也这么想,但是当我看到某些划片的代码后,我瞬间就明白了
- 分组,是根据已经存在的属性来归类,分组的名字是已经存在的属性
- 划片,是根据已经存在的属性来计算一个真假值,然后根据计算出来的真假值归类
分组可以分成 N 多组,划片只有两组,要么属于,要么不属于
元素划片 ( Partitioning Elements )
流收集器类 Collectors
提供了 partitioningBy()
函数用于元素划片,该方法接受一个谓词,然后将结果分成 true
以满足谓词标准,而 false
则不是
partitioningBy()
方法原型
partitioningBy()
方法的原型如下
Collector<T,?,Map<Boolean,List<T>>> partitioningBy(Predicate<? super T> predicate)
从返回的结果 Map<Boolean,List<T>
可以看出,划片只会划出两组
范例
例如下面的代码,用于找出高于平均薪水的那些雇员
Double averageSalary = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary)); Map<Boolean, List<Employee>> portionedEmployees = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > averageSalary)); System.out.println(averageSalary); System.out.println(portionedEmployees
使用命令 javac MyCollectors.java && java MyCollectors
运行代码,输出结果如下
$ javac MyCollectors.java && java MyCollectors 260.79 {false=[Employee(E123,John Nhoj,200.99,IT), Employee(E323,Yogen Rai,200.99,Sales)], true=[Employee(E223,South Htuos,299.99,Sales), Employee(E133,Reet Teer,300.99,IT), Employee(E143,Prateema Rai,300.99,Benefits)]}
对元素划片的结果进行过滤
partitioningBy()
方法还有一个重载的版本,接收两个参数,第二个参数则可用于对划片的结果进行进一步处理,比如统计或计算总和等等
方法原型如下
Collector<T,?,Map<Boolean,D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T,A,D> downstream)
范例
我们可以使用 partitioningBy()
方法对雇员进行划片,然后分别计算高于平均值的雇员的薪水的平均值和低于平均值的雇员薪水的平均值
Map<Boolean, Double> averageSalary2 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > averageSalary,Collectors.averagingDouble(Employee::getSalary))); System.out.println(averageSalary2);
运行以上代码,输出结果如下
{false=200.99, true=300.6566666666667}
结束语
关于划片的知识,其实看起来很少,但要用得精用的妙,却要下不少的功夫,大家可以自己细细琢磨
最后,贴上本章节所有的源码,你可以直接运行
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.TreeMap; 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); Double averageSalary = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary)); Map<Boolean, List<Employee>> portionedEmployees = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > averageSalary)); System.out.println(averageSalary); System.out.println(portionedEmployees); Map<Boolean, Double> averageSalary2 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > averageSalary,Collectors.averagingDouble(Employee::getSalary))); System.out.println(averageSalary2); } }
目前尚无回复