收集器用法详解与多级分组和分区 为什么在collectors类中定义一个静态内部类? static class CollectorImpl<T, A, R> implements Collector<T, A, R>
设计上,本身就是一个辅助类,是一个工厂。作用是给开发者提供常见的收集器实现。提供的方法都是静态方法,可以直接调用。
函数式编程最大的特点:表示做什么,而不是如何做。开发者更注重如做什么,底层实现如何做。
/** * Implementations of {@link Collector} that implement various useful reduction * operations, such as accumulating elements into collections, summarizing * elements according to various criteria, etc. 没有实现的方法,可以自己去编写收集器。 * <p>The following are examples of using the predefined collectors to perform * common mutable reduction tasks: * 举例: * <pre>{@code * // Accumulate names into a List 名字加入到一个集合。 * List<String> list = people.stream().map(Person::getName).collect(Collectors.toList()); * * // Accumulate names into a TreeSet 名字加入到一个Set。 待排序的集合。 * Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new)); * * // Convert elements to strings and concatenate them, separated by commas * String joined = things.stream() * .map(Object::toString) * .collect(Collectors.joining(", ")); * * // Compute sum of salaries of employee 计算员工工资的总数。 * int total = employees.stream() * .collect(Collectors.summingInt(Employee::getSalary))); * * // Group employees by department 对员工进行分组。 * Map<Department, List<Employee>> byDept * = employees.stream() * .collect(Collectors.groupingBy(Employee::getDepartment)); * * // Compute sum of salaries by department 根据部门计算工资的总数。 * Map<Department, Integer> totalByDept * = employees.stream() * .collect(Collectors.groupingBy(Employee::getDepartment, * Collectors.summingInt(Employee::getSalary))); * * // Partition students into passing and failing 将学生进行分区。 * Map<Boolean, List<Student>> passingFailing = * students.stream() * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD)); * * }</pre> * * @since 1.8 提供了常见的方法。没有的话可以去自定义。 */ public final class Collectors { 举例。collector中的方法应用: public static void main(String[] args) { Student student1 = new Student("zhangsan", 80); Student student2 = new Student("lisi", 90); Student student3 = new Student("wangwu", 100); Student student4 = new Student("zhaoliu", 90); Student student5 = new Student("zhaoliu", 90); List<Student> students = Arrays.asList(student1, student2, student3, student4, student5); //list 转换成一个流,再转换成一个集合. List<Student> students1 = students.stream().collect(Collectors.toList()); students1.forEach(System.out::println); System.out.println("- - - - - - -"); // collect 方法底层原理介绍. //有多种方法可以实现同一个功能.什么方式更好呢? 越具体的方法越好. 减少自动装箱拆箱操作. System.out.println("count:" + students.stream().collect(Collectors.counting())); System.out.println("count:" + (Long) students.stream().count()); System.out.println("- - - - - - - -"); //举例练习 // 找出集合中分数最低的学生,打印出来. students.stream().collect(minBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println); // 找出集合中分数最大成绩 students.stream().collect(maxBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println); // 求平均值 System.out.println(students.stream().collect(averagingInt(Student::getScore))); // 求分数的综合 System.out.println(students.stream().collect(summingInt(Student::getScore))); // 求各种汇总信息 结果为IntSummaryStatistics{count=5, sum=450, min=80, average=90.000000, max=100} System.out.println(students.stream().collect(summarizingInt(Student::getScore))); System.out.println(" - - - - - "); // 字符串的拼接 结果为:zhangsanlisiwangwuzhaoliuzhaoliu System.out.println(students.stream().map(Student::getName).collect(joining())); //拼接加分隔符 结果为:zhangsan,lisi,wangwu,zhaoliu,zhaoliu System.out.println(students.stream().map(Student::getName).collect(joining(","))); // 拼接加前后缀 结果为:hello zhangsan,lisi,wangwu,zhaoliu,zhaoliu world System.out.println(students.stream().map(Student::getName).collect(joining(",", "hello ", " world"))); System.out.println("- - - - - - "); // group by 多层分组 // 根据分数和名字进行分组 输出结果为: // {80={zhangsan=[Student{name='zhangsan', score=80}]}, // 100={wangwu=[Student{name='wangwu', score=100}]}, // 90={lisi=[Student{name='lisi', score=90}], zhaoliu=[Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]}} Map<Integer, Map<String, List<Student>>> collect = students.stream().collect(groupingBy(Student::getScore, groupingBy(Student::getName))); System.out.println(collect); System.out.println("- - - - - - - "); // partitioningBy 多级分区 输出结果为:{false=[Student{name='zhangsan', score=80}], true=[Student{name='lisi', score=90}, Student{name='wangwu', score=100}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]} Map<Boolean, List<Student>> collect1 = students.stream().collect(partitioningBy(student -> student.getScore() > 80)); System.out.println(collect1); // 按照大于80分区,再按照90分区 //输出结果为:{false={false=[Student{name='zhangsan', score=80}], true=[]}, true={false=[Student{name='lisi', score=90}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}], true=[Student{name='wangwu', score=100}]}} Map<Boolean, Map<Boolean, List<Student>>> collect2 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, partitioningBy(student -> student.getScore() > 90))); System.out.println(collect2); //分区, 然后求出每个分组中的个数. 结果为:{false=1, true=4} Map<Boolean, Long> collect3 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, counting())); System.out.println(collect3); System.out.println("- - - - - - - "); //根据名字分组,得到学生的分数 --, 使用collectingAndThen 求最小值,然后整合起来. 最后Optional.get()一定有值. students.stream().collect(groupingBy(Student::getName,collectingAndThen(minBy(Comparator.comparingInt(Student::getScore)), Optional::get))); } Comparator比较器详解与类型推断特例Comparator 比较器。引用了多个default方法。