• Java8--Stream的各种用法(二):collect、Collectors


    Collectors中的方法: 

     

     其中我们常用的是前三个:将流中的元素放到集合中、分组、toMap。 下面我们逐个介绍这些方法的使用.

    基础类: Student

    1. public class Student {
    2. private Integer id;
    3. private String name;
    4. private String className;
    5. private Double score;
    6. private Long timeStamp;
    7. }

    1、将流中的元素放到集合中: 

    1.1 toCollection(Supplier collectionFactory) : 

    1. public static extends Collection> Collector toCollection(Supplier collectionFactory) {
    2. return new CollectorImpl<>(collectionFactory, Collection::add,
    3. (r1, r2) -> { r1.addAll(r2); return r1; },
    4. CH_ID);
    5. }

    示例: 

    1. List studentList = new ArrayList<>();
    2. LinkedList collect = studentList.stream().map(Student::getId).collect(Collectors.toCollection(LinkedList::new));

    1.2  toList() 、toSet() :

    直接上示例: 

    1. List list = studentList.stream().map(Student::getId).collect(Collectors.toList());
    2. Set nameSet = studentList.stream().map(Student::getName).collect(Collectors.toSet());

    2、分组

    2.1 groupingBy 它有三个重载方法: 

    1. public static Collector>> groupingBy(Function classifier) {
    2. return groupingBy(classifier, toList());
    3. }
    4. public static Collector> groupingBy(Function classifier, Collector downstream) {
    5. return groupingBy(classifier, HashMap::new, downstream);
    6. }
    7. public static extends Map> Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream) {
    8. ......
    9. }

    第一个方法只需一个分组参数classifier,内部自动将结果保存到一个map中,每个map的键为 ‘?’ 类型(即classifier的结果类型),值为一个list,这个list中保存在属于这个组的元素。 但是它实际是调用了第二个方法-- Collector 默认为list。而第二个方法实际是调用第三个方法,默认Map的生成方式为HashMap。 第三个方法才是真实完整的分组逻辑处理。

     示例: 

    1. Stream stream = studentList.stream();
    2. Map> m1 = stream.collect(Collectors.groupingBy(Student::getScore));
    3. Map> m2 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.toSet()));
    4. 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类型,值为元素的集合

    两个重载的方法: 

    1. public static Collector>> partitioningBy(Predicatesuper T> predicate) {
    2. return partitioningBy(predicate, toList());
    3. }
    4. public static Collector> partitioningBy(Predicatesuper T> predicate,
    5. Collectorsuper T, A, D> downstream) {
    6. ......
    7. }

    从上面的重载方法中可以看出,partitioningBy 与 groupingBy 类似, 只不过partitioningBy 生成的map的key的类型限制只能是Boolean类型。

    示例: 

    1. Stream stream = studentList.stream();
    2. Map> m4 = stream.collect(Collectors.partitioningBy(stu -> stu.getScore() > 60));
    3. Map> m5 = stream.collect(Collectors.partitioningBy(stu -> stu.getScore() > 60, Collectors.toSet()));

    3、toMap

    toMap方法是根据给定的键生成器和值生成器生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。

    toMap也有三个重载的方法: 

    1. public static Collector> toMap(Function keyMapper,Function valueMapper) {
    2. return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
    3. }
    4. public static Collector> toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction) {
    5. return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
    6. }
    7. public static extends Map> Collector toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction,Supplier mapSupplier){
    8. ......
    9. }

    三个重载的方法,最终都是调用第三个方法来实现, 第一个方法中默认指定了key重复的处理方式和map的生成方式; 而第二个方法默认指定了map的生成方式,用户可以自定义key重复的处理方式。

    示例: 

    1. Map map1 = stream.collect(Collectors.toMap(Student::getId, v->v));
    2. Map map2 = stream.collect(Collectors.toMap(Student::getId, Student::getName, (a, b)->a));
    3. Map map3 = stream.collect(Collectors.toMap(Student::getId, Student::getName, (a, b)->a, HashMap::new));
    toConcurrentMap的使用与toMap基本一致, 只不过toConcurrentMap 用于处理并发请求,它生成的map是 ConcurrentHashMap
    

    4、元素拼接joining

    三个重载方法: 

    1. joining() : 没有分隔符和前后缀,直接拼接
    2. joining(CharSequence delimiter) : 指定元素间的分隔符
    3. joining(CharSequence delimiter,CharSequence prefix, CharSequence suffix):  指定分隔符和整个字符串的前后缀。
    1. Stream stream = Stream.of("1", "2", "3", "4", "5", "6");
    2. String s = stream.collect(Collectors.joining(",", "prefix", "suffix"));

    joining 之前,Stream 必须是Stream 类型

    5、类型转换

    mapping:这个映射是首先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。 类似与Stream的map方法。

    collectingAndThen:在归纳动作结束之后,对归纳的结果进行再处理。

    1. Stream stream = studentList.stream();
    2. List idList = stream.collect(Collectors.mapping(Student::getId, Collectors.toList()));
    3. Integer size = stream.collect(Collectors.collectingAndThen(Collectors.mapping(Student::getId, Collectors.toList()), o -> o.size()));

    6、聚合

    1. counting: 同 stream.count()
    2. minBy:  同stream.min()
    3. maxBy: 同stream.max()
    4. summingInt: 
    5. summingLong:
    6. summingDouble:
    7. averagingInt:
    8. averagingLong:
    9. averagingDouble:
    1. Long count = stream.collect(Collectors.counting());
    2. stream.count();
    3. stream.collect(Collectors.minBy((a,b)-> a.getId() - b.getId()));
    4. stream.min(Comparator.comparingInt(Student::getId));
    5. stream.collect(Collectors.summarizingInt(Student::getId));
    6. stream.collect(Collectors.summarizingLong(Student::getTimeStamp));
    7. stream.collect(Collectors.averagingDouble(Student::getScore));

    7、reducing

    reducing方法有三个重载方法,其实是和Stream里的三个reduce方法对应的,二者是可以替换使用的,作用完全一致,也是对流中的元素做统计归纳作用。

    1. public static Collector> reducing(BinaryOperator op) {
    2. ......
    3. }
    4. public static Collector reducing(T identity, BinaryOperator op) {
    5. ......
    6. }
    7. public static Collector reducing(U identity,Function mapper, BinaryOperator op) {
    8. ......
    9. }

    示例:

    1. List list2 = Arrays.asList("123","456","789","qaz","wsx","edc");
    2. Optional optional = list2.stream().map(String::length).collect(Collectors.reducing(Integer::sum));
    3. Integer sum1 = list2.stream().map(String::length).collect(Collectors.reducing(0, Integer::sum));
    4. Integer sum2 = list2.stream().limit(4).collect(Collectors.reducing(0, String::length, Integer::sum));

    扩展: 

    实际运用中,可能会用到比较复杂的 groupingBy、mapping、toMap 嵌套、组合使用,进行多级分组处理数据。如: 

    1. Stream stream = studentList.stream();
    2. // 根据score分组,并提取ID作为集合元素
    3. Map> map1 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.mapping(Student::getId, Collectors.toList())));
    4. // 根据score分组, 并将ID和name组成map作为元素
    5. Map> map2 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.toMap(Student::getId, Student::getName)));
    6. // 先根据score分组,再根据name进行二次分组
    7. Map>> map3 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.groupingBy(Student::getName)));

    当然也可以根据我们想要的条件,设置分组的组合条件,只需要替换 Student::getScore ,换成我们想要的条件即可, 如: 

    1. Map> map3 = stream.collect(Collectors.groupingBy(stu -> {
    2. if (stu.getScore() > 60) {
    3. return "PASS";
    4. } else {
    5. return "FAIL";
    6. }
    7. }, Collectors.mapping(Student::getId, Collectors.toList())));

    按照这种思路,我们可以随意处理stream中的元素成我们想要的结果数据。

  • 相关阅读:
    SSM网约车管理系统毕业设计-附源码051630
    海豚调度系列之:任务类型——Flink节点
    T1063 最大跨度值(信息学一本通C++)
    Python中的元类(metaclass)
    挺后悔,我敷衍地回答了“程序员如何提升抽象思维“
    自制手机app的51蓝牙+循迹+OLED显示速度小车
    霸榜SPC-1,成立才3年多,这家中国的存储初创公司凭什么?
    【Linux】日志 日志管理服务 日志轮替
    ssm心理测验系统的设计与实现毕业设计-附源码211710
    如何3分钟,快速开发一个新功能
  • 原文地址:https://blog.csdn.net/zhoushimiao1990/article/details/128080919