Collectors中的方法:

其中我们常用的是前三个:将流中的元素放到集合中、分组、toMap。 下面我们逐个介绍这些方法的使用.
基础类: Student
- public class Student {
- private Integer id;
-
- private String name;
-
- private String className;
-
- private Double score;
-
- private Long timeStamp;
- }
1.1 toCollection(Supplier
- public static
extends Collection> Collector toCollection(Supplier collectionFactory) { - return new CollectorImpl<>(collectionFactory, Collection
::add, - (r1, r2) -> { r1.addAll(r2); return r1; },
- CH_ID);
- }
示例:
- List
studentList = new ArrayList<>(); -
- LinkedList
collect = studentList.stream().map(Student::getId).collect(Collectors.toCollection(LinkedList::new));
1.2 toList() 、toSet() :
直接上示例:
- List
list = studentList.stream().map(Student::getId).collect(Collectors.toList()); -
- Set
nameSet = studentList.stream().map(Student::getName).collect(Collectors.toSet());
2.1 groupingBy 它有三个重载方法:
- public static
Collector>> groupingBy(Function classifier) { - return groupingBy(classifier, toList());
- }
-
- public static
Collector> groupingBy(Function classifier, Collector downstream) { - return groupingBy(classifier, HashMap::new, downstream);
- }
-
- public static
extends Map> Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream) { - ......
- }
第一个方法只需一个分组参数classifier,内部自动将结果保存到一个map中,每个map的键为 ‘?’ 类型(即classifier的结果类型),值为一个list,这个list中保存在属于这个组的元素。 但是它实际是调用了第二个方法-- Collector 默认为list。而第二个方法实际是调用第三个方法,默认Map的生成方式为HashMap。 第三个方法才是真实完整的分组逻辑处理。
示例:
- Stream
stream = studentList.stream(); -
- Map
> m1 = stream.collect(Collectors.groupingBy(Student::getScore)); -
- Map
> m2 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.toSet())); -
- Map
> m3 = stream.collect(Collectors.groupingBy(Student::getScore,TreeMap::new, Collectors.toSet()));
2.2 groupingByConcurrent
返回一个并发Collector收集器对T类型的输入元素执行"group by"操作, 也有三个重载的方法, 其使用与groupingBy 基本相同。
2.3 partitioningBy
该方法将流中的元素按照给定的校验规则的结果分为两个部分,放到一个map中返回,map的键是Boolean类型,值为元素的集合
两个重载的方法:
- public static
Collector>> partitioningBy(Predicate super T> predicate) { - return partitioningBy(predicate, toList());
- }
-
- public static
Collector> partitioningBy(Predicate super T> predicate, - Collector super T, A, D> downstream) {
- ......
- }
从上面的重载方法中可以看出,partitioningBy 与 groupingBy 类似, 只不过partitioningBy 生成的map的key的类型限制只能是Boolean类型。
示例:
- Stream
stream = studentList.stream(); -
- Map
> m4 = stream.collect(Collectors.partitioningBy(stu -> stu.getScore() > 60)); -
- Map
> m5 = stream.collect(Collectors.partitioningBy(stu -> stu.getScore() > 60, Collectors.toSet()));
toMap方法是根据给定的键生成器和值生成器生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。
toMap也有三个重载的方法:
- public static
Collector> toMap(Function keyMapper,Function valueMapper) { - return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
- }
-
- public static
Collector> toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction) { - return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
- }
-
- public static
extends Map> Collector toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction,Supplier mapSupplier){ - ......
- }
三个重载的方法,最终都是调用第三个方法来实现, 第一个方法中默认指定了key重复的处理方式和map的生成方式; 而第二个方法默认指定了map的生成方式,用户可以自定义key重复的处理方式。
示例:
- Map
map1 = stream.collect(Collectors.toMap(Student::getId, v->v)); - Map
map2 = stream.collect(Collectors.toMap(Student::getId, Student::getName, (a, b)->a)); - Map
map3 = stream.collect(Collectors.toMap(Student::getId, Student::getName, (a, b)->a, HashMap::new));
toConcurrentMap的使用与toMap基本一致, 只不过toConcurrentMap 用于处理并发请求,它生成的map是 ConcurrentHashMap
三个重载方法:
- Stream
stream = Stream.of("1", "2", "3", "4", "5", "6"); - String s = stream.collect(Collectors.joining(",", "prefix", "suffix"));
joining 之前,Stream 必须是Stream
mapping:这个映射是首先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。 类似与Stream的map方法。
collectingAndThen:在归纳动作结束之后,对归纳的结果进行再处理。
- Stream
stream = studentList.stream(); -
- List
idList = stream.collect(Collectors.mapping(Student::getId, Collectors.toList())); -
- Integer size = stream.collect(Collectors.collectingAndThen(Collectors.mapping(Student::getId, Collectors.toList()), o -> o.size()));
- Long count = stream.collect(Collectors.counting());
- stream.count();
- stream.collect(Collectors.minBy((a,b)-> a.getId() - b.getId()));
- stream.min(Comparator.comparingInt(Student::getId));
- stream.collect(Collectors.summarizingInt(Student::getId));
- stream.collect(Collectors.summarizingLong(Student::getTimeStamp));
- stream.collect(Collectors.averagingDouble(Student::getScore));
reducing方法有三个重载方法,其实是和Stream里的三个reduce方法对应的,二者是可以替换使用的,作用完全一致,也是对流中的元素做统计归纳作用。
- public static
Collector> reducing(BinaryOperator op) { - ......
- }
-
- public static
Collector reducing(T identity, BinaryOperator op) { - ......
- }
-
- public static
Collector reducing(U identity,Function mapper, BinaryOperator op) { - ......
- }
示例:
- List
list2 = Arrays.asList("123","456","789","qaz","wsx","edc"); -
- Optional
optional = list2.stream().map(String::length).collect(Collectors.reducing(Integer::sum)); -
- Integer sum1 = list2.stream().map(String::length).collect(Collectors.reducing(0, Integer::sum));
-
- Integer sum2 = list2.stream().limit(4).collect(Collectors.reducing(0, String::length, Integer::sum));
实际运用中,可能会用到比较复杂的 groupingBy、mapping、toMap 嵌套、组合使用,进行多级分组处理数据。如:
- Stream
stream = studentList.stream(); - // 根据score分组,并提取ID作为集合元素
- Map
> map1 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.mapping(Student::getId, Collectors.toList()))); - // 根据score分组, 并将ID和name组成map作为元素
- Map
> map2 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.toMap(Student::getId, Student::getName))); - // 先根据score分组,再根据name进行二次分组
- Map
>> map3 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.groupingBy(Student::getName)));
当然也可以根据我们想要的条件,设置分组的组合条件,只需要替换 Student::getScore ,换成我们想要的条件即可, 如:
- Map
> map3 = stream.collect(Collectors.groupingBy(stu -> { - if (stu.getScore() > 60) {
- return "PASS";
- } else {
- return "FAIL";
- }
- }, Collectors.mapping(Student::getId, Collectors.toList())));
按照这种思路,我们可以随意处理stream中的元素成我们想要的结果数据。