写点什么

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

  • 2023-09-14
    北京
  • 本文字数:2642 字

    阅读完需:约 9 分钟

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 可以获取数组对应的流。


//StringStream<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方法中写入筛选条件,将过滤后的数据组成新的listlist.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 转载请注明来源

发布于: 刚刚阅读数: 4
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
Stream流处理快速上手最佳实践 | 京东物流技术团队_京东云_京东科技开发者_InfoQ写作社区