简单条件分组
- 无明确条件指定,对应属性值的类别有多少个,分组就有多少个
Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(Student::getName));
这里我们使用方法引用(类名::实例方法名)替代lambda表达式(s -> s.getName())的方式来指定classifier分类器,使集合按Student的name来分组。
注意到分组后的返回类型是Map<String, List>,结果集中会将name作为key,对应的Student集合作为value返回。
复杂条件分组
- 传入lambda表达式,根据属性学生成绩的不同值等级来分组,有明确的条件指定
Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(student->{
if (student.getScore() >= 90) {
return "优秀";
} else if (student.getScore() >= 80) {
return "良好";
} else {
return "一般";
}
}));
分组之后,再用收集器统计
如果按name分组后,想求出每组学生的数量,就需要借助groupingBy另一个重载的方法
public static Collector groupingBy(Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream){
//...
}
第二个参数downstream还是一个收集器Collector对象,也就是说我们可以先将classifier作为key进行分组,然后将分组后的结果交给downstream收集器再进行处理
//按name分组 得出每组的学生数量 使用重载的groupingBy方法,第二个参数是分组后的操作
Map<String, Long> collect1 = studentList.stream()
.collect(Collectors.groupingBy(Student::getName, Collectors.counting()));
//按名字分组,求出每个学生平均分
Map<String, Double> collect2 = studentList.stream()
.collect(Collectors.groupingBy(Student::getName, Collectors.averagingDouble(Student::getScore)));
分区
我们现在再加一个需求,分别统计一下及格和不及格的学生(分数是否>=60)
这时候符合Stream分区的概念了,Stream分区会将集合中的元素按条件分成两部分结果,key是Boolean类型,value是结果集,满足条件的key是true
Map<Boolean, List<Student>> collect3 = students.stream()
.collect(Collectors.partitioningBy(student -> student.getScore() >= 60));
System.out.println(collect3.get(true));//输出及格的Student
System.out.println(collect3.get(false));//输出不及格的Student