Stream流处理快速上手最佳实践 | 京东物流技术团队
一 引言
JAVA1.8得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
二 常用方法介绍
2.1 获取Stream流
所有的 Collection 集合都可以通过 stream 默认方法获取流;
java.util.Collection 接口中加入了default方法 stream 用来获取流,所以其所有实现类均可获取流。
ArrayList<XyBug> xyBugList = new ArrayList(); Stream<XyBug> stream = xyBugList.stream();
Stream 接口的静态方法 of 可以获取数组对应的流。
//String Stream<String> stream = Stream.of("aa", "bb", "cc"); //数组 String[] arr = {"aa", "bb", "cc"}; Stream<String> stream7 = Stream.of(arr); Integer[] arr2 = {11, 22, 33}; Stream<Integer> stream8 = Stream.of(arr2); //对象 XyBug xyBug1 = new XyBug(); XyBug xyBug2 = new XyBug(); XyBug xyBug3 = new XyBug(); Stream<XyBug> bugStream = Stream.of(xyBug1, xyBug2, xyBug3);
2.2 Stream 数据处理常用方法
forEach方法
该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理
List<String> 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));
s代表list中的每一个元素,流式处理依次遍历每个元素
->后的代码为每个元素处理逻辑
count方法
count 方法来统计其中的元素个数,返回值为long类型
long count = list.stream().count();
distinct方法
对流中的数据进行去重操作,普通类型可直接去重
//将22、33重复数据去除 Stream.of(22, 33, 22, 11, 33).distinct().collect(Collectors.toList());
自定义类型是根据对象的hashCode和equals来去除重复元素的
XyBug实体类中加@Data注解,hashCode和equals会别重写,在使用distinct方法时判断去重
ArrayList bugList = JSON.parseObject(bugs, ArrayList.class); ArrayList<XyBug> xyBugList = new ArrayList(); List collect = (List) bugList.stream().distinct().collect(Collectors.toList());
通过distinct()方法去重,去重后的数据通过collect(Collectors.toList())组成新6的list
limit方法
方法可以对流进行截取,只取用前n个,参数是一个long型,如果集合当前长度大于参数则进行截取。否则不进行操作
List<String> list = new ArrayList<>(); Collections.addAll(list, "1", "2", "3", "4", "5", "6"); List<String> collect = list.stream().limit(3).collect(Collectors.toList());
将前3个String对象截取,组成新的list
skip方法
如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流,如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流
List<String> list = new ArrayList<>(); Collections.addAll(list, "1", "2", "3", "4", "5", "6"); List<String> collect = list.stream().skip(3).collect(Collectors.toList());
跳过前3个String对象,后三个组成新的list
filter方法
filter用于过滤数据,返回符合过滤条件的数据,可以通过 filter 方法将一个流转换成另一个子集流,该接口接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件
List<String> list = new ArrayList<>(); Collections.addAll(list, "1", "22", "3", "4", "55", "6"); //filter方法中写入筛选条件,将过滤后的数据组成新的list list.stream().filter(s -> s.length() == 2).collect(Collectors.toList());
通过该条语句s -> s.length() == 2,筛选出22、55
map方法
将流中的元素映射到另一个流中,可以将当前流中的T类型数据转换为另一种R类型的流
List<PersonCrDto> laputaCrDtos = queryListLaputaByBeginEndTime(begin, end); //将list中的PersonCrDto对象的userName属性取到,收集成set集合 laputaCrDtos.stream().map(PersonCrDto::getUserName).collect(Collectors.toSet())
将list中的每个对象的userName数据拿到,组成Set集合
stream分组
List<XyBug> list = new ArrayList<>(); Map<String, List<XyBug>> collect = list.stream().collect(Collectors.groupingBy(XyBug::getBugType));
根据bug类型进行分组,分组后会组成map,key是组名,value是组下的数据
stream排序
sort(),默认正序排列,加入reversed()方法后倒叙排列
List<XyBug> list = new ArrayList<>(); //根据createTime正序排列 List<XyBug> collect = list.stream().sorted(Comparator.comparing(XyBug::getCreateTime)).collect(Collectors.toList()); //根据createTime倒叙排列 List<XyBug> collect = list.stream().sorted(Comparator.comparing(XyBug::getCreateTime).reversed()).collect(Collectors.toList());
collect方法
将处理后数据收集为list,collect(Collectors.toList())
将处理后数据收集为set,collect(Collectors.toSet())
根据某个字段值将数据分组map,collect(Collectors.groupingBy(o -> o.value())))
三 实践举例
需求:将bug数据通过orgTierName分组,存储到map中
未使用Stream,需要使用for循环并且进行各种判断,代码行数较多
HashMap<String, List<XyBug>> map = new HashMap<>(); for (XyBug one : bugList){ if(one.getOrgTierName() != null){ if(map.get(one.getOrgTierName()) == null){ List<XyBug> list = new ArrayList(); list.add(one); map.put(one.getOrgTierName(),list); }else { map.get(one.getOrgTierName()).add(one); } } }
使用Stream,一行代码搞定,直观并高效
collectDeptBugMap = bugList.stream().filter(o -> o.getOrgTierName() != null).collect(Collectors.groupingBy(o -> o.getOrgTierName()));
四 总结
Stream是对集合(Collection)对象功能的增强,能对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作,提高编程效率、简洁性和程序可读性。本文通过简单举例,希望帮助读者快速上手使用流处理,Stream流处理功能非常强全,更多方法请参考API文档。
作者:京东物流 杨靖平
来源:京东云开发者社区 自猿其说Tech 转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
阿里云 PAI - 灵骏大模型训练工具 Pai-Megatron-Patch 正式开源!
作者: 李鹏,王明,施晨,黄俊 导读 随着深度学习大语言模型的不断发展,其模型结构和量级在快速演化,依托大模型技术的应用更是层出不穷。对于广大开发者来说不仅要考虑如何在复杂多变的场景下有效的将大模型消耗的算力发挥出来,还要应对大模型的持续迭代。开发简单易用的大模型训练工具就成了应对以上问题广受关注的技术方向,让开发者专注于大模型解决方案的开发,降低大模型训练加速性能优化和训练/推理全流程搭建的人力开发成本。阿里云机器学习平台PAI开源了业内较早投入业务应用的大模型训练工具Pai-Megatron-Patch,本文将详解Pai-Megatron-Patch的设计原理和应用。 Pai-Megatron-Patch是什么 Pai-Megatron-Patch工具是阿里云机器学习平台PAI算法团队研发,基于阿里云智算服务PAI-灵骏平台的大模型最佳实践解决方案配套工具,旨在帮助大模型开发者快速上手灵骏产品,完成大语言模型(LLM)的高效分布式训练,有监督指令微调,模型离线推理验证等完整大模型开发链路。该项目提供了业界主流开源大模型基于Megatron-LM的训练&离线推理验证流程,方便...
- 下一篇
618京东到家APP-门详页反爬实战 | 京东云技术团队
一、背景与系统安全需求分析 1. 系统的重要性 上图所示是接口所属位置、对电商平台或在线商店而言,分类查商品都是很重要的,通过为用户提供清晰的商品分类,帮助他们快速找到所需产品,节省浏览时间,提升购物效率,是购物结算产生GMV的核心环节。那么电商平台为什么都很看重商品信息的爬取? a. 数据收集和分析:这些数据对于市场研究、竞争分析、价格比较等方面非常有价值。可获得有关产品趋势、消费者偏好、价格波动等信息,有助于企业进行决策和制定营销策略。 b. 价格监控和动态调整:可以实时跟踪和监控竞争对手的价格变化。企业可以根据市场情况及时调整自己的产品定价,保持竞争力,并更好地满足消费者需求等。 2. 风险评估 a. 系统安全、以及触发各种报警 b. 数据安全 c. 带宽和服务器资源消耗 d. 不良竞争等; 3. 618期间的爬虫问题 由于这个接口还比较特殊,我们在3个版本前刚迁移color网关,其他低版本使用的是另一个物理网关我们暂且称: B网关,另外在B网关还由于一些历史原因区分了Get 和 Post 两个接口对客户端提供。所以一共是3个接口。 客户端有多平台:h5, 微信小程序、支付宝小程...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Hadoop3单机部署,实现最简伪集群
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度