Collectors
Collector接口中方法的实现决定了如何对流执行归约操作。但Collectors实用类提供了很多静态工厂方法,可以方便地创建常见收集器的实例,只要拿来用就可以了。
归约操作
Collectors.counting
// 集合个数 Long collect = employees.stream().collect(Collectors.counting()); System.out.println(collect); System.out.println(employees.stream().count());Collectors.maxBy 和 Collectors.minBy
//最大最小值 Optional<Employee> collect1 = employees.stream() .collect(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary))); System.out.println(collect1.get()); Optional<Employee> collect2 = employees.stream() .collect(Collectors.minBy(Comparator.comparingDouble(Employee::getSalary))); System.out.println(collect2.get());Collectors.summingInt
// 汇总 Integer collect3 = employees.stream().collect(Collectors.summingInt(Employee::getId)); System.out.println(collect3);Collectors.summingLong和Collectors.summingDouble方法的作用完全一样,可以用于求和字段为long或double的情况。
Collectors.averagingInt,连同对应的averagingLong和averagingDouble可以计算数值的平均数;
summarizingInt,summarizingLong和summarizingDouble可以计算总和、平均值、最大值和最小值;得到IntSummaryStatistics,LongSummaryStatistics和DoubleSummaryStatistics
Collectors.joining
joining工厂方法返回的收集器会把对流中每一个对象应用toString方法得到的所有字符串连接成一个字符串。
// 2个重载版本 List<Employee> employees = EmployeeData.getEmployees(); String collect = employees.stream().map(Employee::getName) .collect(Collectors.joining()); System.out.println(collect); // 添加分隔符 String collect1 = employees.stream().map(Employee::getName).collect(Collectors.joining(",")); System.out.println(collect1); // 添加分隔符,开头 结尾 String collect2 = employees.stream().map(Employee::getName) .collect(Collectors.joining(",", "开头", "结尾")); System.out.println(collect2);Collectors.reducing
需要三个参数:
1.第一个参数是归约操作的起始值,也是流中没有元素时的返回值,所以很显然对于数值和而言0是一个合适的值。
2.转换函数
3.是一个BinaryOperator,将两个项目累积成一个同类型的值
List<Employee> employees = EmployeeData.getEmployees(); Integer collect = employees.stream().collect(Collectors.reducing(0, Employee::getId, (a, b) -> a + b)); System.out.println(collect); Optional<Employee> collect3 = employees.stream() .collect(Collectors.reducing((a, b) -> a.getSalary() > b.getSalary() ? a : b)); System.out.println(collect3); Optional<Integer> collect1 = Stream.of(1, 2, 3, 4, 5).collect(Collectors.reducing((a, b) -> a + b)); System.out.println(collect1.get()); Integer collect2 = Stream.of(1, 2, 3, 4, 5).collect(Collectors.reducing(10, (a, b) -> a + b)); System.out.println(collect2);
分组
Collectors.groupingBy。
List<Employee> employees = EmployeeData.getEmployees();
// 按工资分组
Map<Double, List<Employee>> collect = employees.stream()
.collect(Collectors.groupingBy(Employee::getSalary));
System.out.println(collect);
Map<String, List<Employee>> collect1 = employees.stream().collect(Collectors.groupingBy(employee -> {
if (employee.getSalary() > 9000) {
return "gao";
} else if (employee.getSalary() > 500) {
return "zhong";
} else {
return "di";
}
}));
System.out.println(collect1);
操作分组的元素
Collectors类重载了工厂方法groupingBy,除了常见的分类函数,它的第二变量也接受一个Collector类型的参数。
Map<Double, List<String>> collect2 = employees.stream()
.collect(Collectors.groupingBy(Employee::getSalary, Collectors.mapping(Employee::getName, Collectors.toList())));
System.out.println(collect2);
Collectors类通过mapping方法提供了另一个Collector函数,它接受一个映射函数和另一个Collector函数作为参数。作为参数的Collector会收集对每个元素执行该映射函数的运行结果。
有三个参数重载版本,多增加一个map生成工厂
HashMap<Double, List<Integer>> collect3 = employees.stream()
.collect(Collectors.groupingBy(Employee::getSalary, HashMap::new, Collectors
.mapping(Employee::getAge, Collectors.toList())));
多级分组
要实现多级分组,可以使用一个由双参数版本的Collectors.groupingBy工厂方法创建的收集器,它除了普通的分类函数之外,还可以接受collector类型的第二个参数。那么要进行二级分组的话,可以把一个内层groupingBy传递给外层groupingBy,并定义一个为流中项目分类的二级标准。
// 多级分组
Map<Double, Map<Integer, List<Employee>>> collect4 = employees.stream().collect
(Collectors.groupingBy(Employee::getSalary,Collectors.groupingBy(Employee::getAge)));
按子组收集数据
把收集器的结果转换为另一种类型
Map<Double, Optional<Employee>> collect5 = employees.stream(). collect(Collectors.groupingBy(Employee::getSalary, Collectors.maxBy(Comparator.comparing(Employee::getName)))); // 把收集器的结果转换为另一种类型 Map<Double, Employee> collect6 = employees.stream(). collect(Collectors.groupingBy(Employee::getSalary, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Employee::getId)), Optional::get)));与groupingBy联合使用的其他收集器
Map<Double, Set<String>> collect7 = employees.stream().collect( Collectors.groupingBy(Employee::getSalary, Collectors.mapping(Employee::getName, Collectors.toSet())));联合使用其他的收集器,可以产生各种类型数据。继续摸索使用中
分区
分区函数返回一个布尔值,这意味着得到的分组Map的键类型是Boolean,于是它最多可以分为两组——true是一组,false是一组。
List<Employee> employees = EmployeeData.getEmployees();
Map<Boolean, List<Employee>> collect = employees.stream()
.collect(Collectors.partitioningBy(employee -> employee.getSalary() > 1000));
总结