• Stream流处理快速上手最佳实践 | 京东物流技术团队


    一 引言

    JAVA1.8得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

    二 常用方法介绍

    2.1 获取Stream流

    所有的 Collection 集合都可以通过 stream 默认方法获取流;

    java.util.Collection 接口中加入了default方法 stream 用来获取流,所以其所有实现类均可获取流。

    ArrayList xyBugList = new ArrayList();
    Stream stream = xyBugList.stream();
    
    
    
    • 1
    • 2
    • 3
    • 4

    Stream 接口的静态方法 of 可以获取数组对应的流。

    //String
    Stream stream = Stream.of("aa", "bb", "cc");
    //数组
    String[] arr = {"aa", "bb", "cc"};
    Stream stream7 = Stream.of(arr);
    Integer[] arr2 = {11, 22, 33};
    Stream stream8 = Stream.of(arr2);
    //对象
    XyBug xyBug1 = new XyBug();
    XyBug xyBug2 = new XyBug();
    XyBug xyBug3 = new XyBug();
    Stream bugStream = Stream.of(xyBug1, xyBug2, xyBug3);
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.2 Stream 数据处理常用方法

    forEach方法

    该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理

    List list = new ArrayList<>();
    Collections.addAll(list, "str1", "str2", "str3", "str4", "str5", "str6");
    list.stream().forEach((String s) -> {
      System.out.println(s);
      });
    //简写
    list.stream().forEach(s -> System.out.println(s));
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    s代表list中的每一个元素,流式处理依次遍历每个元素

    ->后的代码为每个元素处理逻辑

    count方法

    count 方法来统计其中的元素个数,返回值为long类型

    long count = list.stream().count();
    
    
    
    • 1
    • 2
    • 3
    distinct方法

    对流中的数据进行去重操作,普通类型可直接去重

    //将22、33重复数据去除
    Stream.of(22, 33, 22, 11, 33).distinct().collect(Collectors.toList());
    
    
    
    • 1
    • 2
    • 3
    • 4

    自定义类型是根据对象的hashCode和equals来去除重复元素的

    XyBug实体类中加@Data注解,hashCode和equals会别重写,在使用distinct方法时判断去重

    ArrayList bugList = JSON.parseObject(bugs, ArrayList.class);
    ArrayList xyBugList = new ArrayList();
    List collect = (List) bugList.stream().distinct().collect(Collectors.toList());
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    通过distinct()方法去重,去重后的数据通过collect(Collectors.toList())组成新6的list

    limit方法

    方法可以对流进行截取,只取用前n个,参数是一个long型,如果集合当前长度大于参数则进行截取。否则不进行操作

    List list = new ArrayList<>();
    Collections.addAll(list, "1", "2", "3", "4", "5", "6");
    List collect = list.stream().limit(3).collect(Collectors.toList());
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    将前3个String对象截取,组成新的list

    skip方法

    如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流,如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流

    List list = new ArrayList<>();
    Collections.addAll(list, "1", "2", "3", "4", "5", "6");
    List collect = list.stream().skip(3).collect(Collectors.toList());
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    跳过前3个String对象,后三个组成新的list

    filter方法

    filter用于过滤数据,返回符合过滤条件的数据,可以通过 filter 方法将一个流转换成另一个子集流,该接口接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件

    List list = new ArrayList<>();
    Collections.addAll(list, "1", "22", "3", "4", "55", "6");
    //filter方法中写入筛选条件,将过滤后的数据组成新的list
    list.stream().filter(s -> s.length() == 2).collect(Collectors.toList());
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通过该条语句s -> s.length() == 2,筛选出22、55

    map方法

    将流中的元素映射到另一个流中,可以将当前流中的T类型数据转换为另一种R类型的流

    List laputaCrDtos = queryListLaputaByBeginEndTime(begin, end);
    //将list中的PersonCrDto对象的userName属性取到,收集成set集合
    laputaCrDtos.stream().map(PersonCrDto::getUserName).collect(Collectors.toSet())
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    将list中的每个对象的userName数据拿到,组成Set集合

    stream分组
    List list = new ArrayList<>();
    Map> collect = list.stream().collect(Collectors.groupingBy(XyBug::getBugType));
    
    
    
    • 1
    • 2
    • 3
    • 4

    根据bug类型进行分组,分组后会组成map,key是组名,value是组下的数据

    stream排序

    sort(),默认正序排列,加入reversed()方法后倒叙排列

    List list = new ArrayList<>();
    //根据createTime正序排列
    List collect = list.stream().sorted(Comparator.comparing(XyBug::getCreateTime)).collect(Collectors.toList());
    //根据createTime倒叙排列
    List collect = list.stream().sorted(Comparator.comparing(XyBug::getCreateTime).reversed()).collect(Collectors.toList());
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    collect方法

    将处理后数据收集为list,collect(Collectors.toList())

    将处理后数据收集为set,collect(Collectors.toSet())

    根据某个字段值将数据分组map,collect(Collectors.groupingBy(o -> o.value())))

    三 实践举例

    需求:将bug数据通过orgTierName分组,存储到map中

    未使用Stream,需要使用for循环并且进行各种判断,代码行数较多

    HashMap> map = new HashMap<>();
    for (XyBug one : bugList){
        if(one.getOrgTierName() != null){
            if(map.get(one.getOrgTierName()) == null){
                List list = new ArrayList();
                list.add(one);
                map.put(one.getOrgTierName(),list);
            }else {
                map.get(one.getOrgTierName()).add(one);
            }
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    使用Stream,一行代码搞定,直观并高效

    collectDeptBugMap = bugList.stream().filter(o -> o.getOrgTierName() != null).collect(Collectors.groupingBy(o -> o.getOrgTierName()));
    
    
    
    • 1
    • 2
    • 3

    四 总结

    Stream是对集合(Collection)对象功能的增强,能对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作,提高编程效率、简洁性和程序可读性。本文通过简单举例,希望帮助读者快速上手使用流处理,Stream流处理功能非常强全,更多方法请参考API文档。

    作者:京东物流 杨靖平

    来源:京东云开发者社区  自猿其说Tech 转载请注明来源

  • 相关阅读:
    Mac和IDE配置
    基于JAVA婚纱影楼服务管理计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    技术变现整体流程
    成集云 | 飞书审批同步金蝶云星空销售订单 | 解决方案
    22-09-20 西安 谷粒商城(04)Redisson、布隆过滤器、AOP赋能自定义注解@GmallCache
    Ubuntu环境变量相关知识
    Multi-Video Temporal Synchronization论文笔记
    战略进攻能力的重要性,要远远高于战略防守能力
    三、RTMP协议 视频Chunk和音频Chunk到底长啥样?
    微服务架构(从无到有)三.构建对象存储服务 1) micro+阿里云oss服务
  • 原文地址:https://blog.csdn.net/JDDTechTalk/article/details/132764598