JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

SpringBoot系列(七):Java8的Stream API,让集合操作更为高效

wys521 2024-12-01 09:30:11 精选教程 26 ℃ 0 评论

本文我们将开个小插曲,分享介绍如何基于Java8提供的Stream特性,高效操作我们的集合,如List、Set、Map等等。其中,将主要介绍Stream特性提供的筛选过滤功能Filter、对象转化功能Map、去重Distinct、排序Sorted、最小值Min以及最大值Max等核心操作。

了解过jdk动态的小伙伴们估计都知道,jdk已经出到12的版本了(是不是有点怀疑目前仍然还在使用jdk1.6、jdk1.5的自己),当然啦,我们都知道,不管jdk怎么升级,其底层核心数据库以及jvm的特性是变化不大的,特别是java8之后的版本,其主要还是以java8作为奠基进行一步步扩张的。如下图所示:

Java8对外提供的特性有很多,Stream便是其中的一大功能特性,除此之外,Java8还提供了接口默认方法、Lambda表达式、函数式接口等等。说起Java8的Stream,其在集合的操作中着实发挥了强大的作用,别的不说,其中的简洁、高效就特别令人眼前一亮。

Stream作为Java8的新特性,主要是基于lambda表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,可以提高编程的效率和代码可读性。

对于Stream的原理,正是其字面上的含义,Stream是将等待被处理的元素看做一种流,而流在管道中传输,并且可以在管道的节点上执行相应的处理操作,包括过滤筛选、去重、排序、聚合等等,元素流在管道中经过中间操作的处理,最后由最终操作如collect等方法得到前面处理的结果。

对于Stream的原理,各位小伙伴也可以网上搜索相应的文章进行深入的研究,在这里我们只做简单性的介绍。在后续的代码实战中,各位小伙伴可以看到上述对于Stream的原理将很好地在代码中得到体现。

值得一提的是,Stream API在执行的具体操作之前,需要先生成“流”,主要有两种方式:

stream() ? 为集合创建串行流

parallelStream() - 为集合创建并行流

下面,我们在com.debug.springboot.server.dto目录下新建一个实体类PersonDto,用于后续的Stream代码实战中,其源代码如下所示:


@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class PersonDto implements Serializable{
 private Integer id;
 private Integer age;
 private String name;
}

其中,我们需要在该实体类中加入Equals()和HashCode()方法,用于后续执行Stream的去重API做铺垫!

另外,也需要在com.debug.springboot.server.utils 包目录下新建一个Java8Util类,用于介绍一些比较突出的Steam API操作。

首先,我们需要在Java8Util类中新建一个可以被共用的对象集合,并采用static静态代码块进行初始化,如下所示:


private static List<PersonDto> list;
 //初始化对象集合
 static {
 list= Lists.newLinkedList();
 PersonDto dto1=new PersonDto(1,21,"赵六");
 PersonDto dto2=new PersonDto(2,20,"张三");
 PersonDto dto3=new PersonDto(3,22,"李四");
 PersonDto dto4=new PersonDto(4,20,"王五");
 list.add(dto1);
 list.add(dto2);
 list.add(dto3);
 list.add(dto4);
 }

1、首先介绍Stream的筛选过滤功能Filter:下面的代码用于筛选过滤出年龄>20的对象集合,筛选过滤出名字为 王五 的对象信息,如下所示:


//筛选功能:filter 结合 collect方法 使用
 public static void method1(){
 //筛选年龄大于20的小伙子
 if (list!=null && !list.isEmpty()){
 System.out.println("\n--filter筛选功能1,结果:");
 List<PersonDto> resList=list.stream().filter(p -> p.getAge() > 20).collect(Collectors.toList());
 System.out.println(resList);
 }
 //筛选名字为 王五 的小伙子
 if (list!=null && !list.isEmpty()){
 System.out.println("\n--filter筛选功能2,结果:");
 List<PersonDto> resList=list.stream().filter(p -> "王五".equals(p.getName())).collect(Collectors.toList());
 System.out.println(resList);
 }
 }

之后,我们可以写一个main方法,直接调用method1(),其运行结果如下图所示:

2、紧接着,我们介绍Stream中的转换功能Map,如有以下的业务场景:当得到一个对象集合之后,要求我们需要抽取出每个对象中的某个字段,组成新的列表,比如抽取这个对象集合中的Id,或者Name,从而组成新的一个列表,源代码如下所示:


//转换map~按照指定的字段/元素属性进行转换:结合 collect 方法使用
 public static void method2(){
 if (list!=null && !list.isEmpty()){
 System.out.println("\n--转换map~按照指定的字段/元素属性进行转换,结果:");
 Set<String> nameSet=list.stream().map(PersonDto::getName).collect(Collectors.toSet());
 System.out.println(nameSet);
 }
 }

运行结果如下图所示:

3、然后,我们介绍一下“对象去重Distinct”的操作,这一操作,我们需要在实体类中加入 @EqualsAndHashCode 的lombok注解,源代码如下所示:


//去重distinct ~ 配合对象的 equals() 和 hashCode()方法
 public static void method3(){
 //TODO:对象去重 - 对象需要实现equals hashCode方法
 list.add(new PersonDto(4,20,"王五"));
 System.out.println("去重以前:"+list);
 List<PersonDto> resList=list.stream().distinct().collect(Collectors.toList());
 System.out.println("去重以后:"+resList);
 }

运行结果如下图所示:

4、顺道,我们介绍一下Stream提供的Sorted排序功能,即我们可以根据对象中的某个字段实施某种排序方式(正序、倒序)等,如下代码所示,我们可以借助Comparator比较器连续先后的对对象集合进行排序:先按照年龄排序、再按照id排序(正序、倒序),源代码如下所示:


//排序sorted
 public static void method4(){
 //按照年龄排序、再按照id排序
 list.add(new PersonDto(0,20,"郑六"));
 if (list!=null && !list.isEmpty()){
 List<PersonDto> resList=list.stream()
 .sorted(Comparator.comparingInt(PersonDto::getAge).thenComparing(Comparator.comparing(PersonDto::getId)))
 .collect(Collectors.toList());
 System.out.println("按照年龄排序、再按照id排序-顺序:\n"+resList);
 }
 //按照年龄排序、再按照id排序 ~ 也可以将最终结果倒序来
 if (list!=null && !list.isEmpty()){
 List<PersonDto> resList=list.stream()
 .sorted(Comparator.comparingInt(PersonDto::getAge).thenComparing(Comparator.comparing(PersonDto::getId)).reversed())
 .collect(Collectors.toList());
 System.out.println("\n按照年龄排序、再按照id排序-最终倒序:\n"+resList);
 }
 }

其运行结果如下图所示:

5、最后,我们介绍一下如果根据对象中某个字段的最大、最小,从而取出整个对象集合中该最小值字段、最大值字段对应的对象记录,源码如下所示:


//最小min、最大max
 public static void method5(){
 if (list!=null && !list.isEmpty()){
 PersonDto p=list.stream()
 .min(Comparator.comparingInt(PersonDto::getId))
 .get();
 System.out.println("\nid最小:"+p);
 }
 if (list!=null && !list.isEmpty()){
 PersonDto p=list.stream()
 .max(Comparator.comparingInt(PersonDto::getAge))
 .get();
 System.out.println("\n年龄最大:"+p);
 }
 }

其运行结果如下图所示:

至此,关于Java8Stream一些常用的操作API,我们已经介绍完毕了,当然啦,除了本文所介绍的一个常用的API操作之外,Stream特性提供的功能操作还远远不止于此,若有小伙伴对Java8的新功能特性感兴趣,可以关注公众号“程序员实战基地”,并回复“java8”,即可免费领取关于java8函数式编程的pdf电子书<Java 8函数式编程>

补充

1、本文涉及到的相关的源代码可以到此地址,check出来进行查看学习:

https://gitee.com/steadyjack/SpringBootTechnology

2、目前Debug已将本文所涉及的内容整理录制成视频教程,感兴趣的小伙伴可以前往观看学习:

http://www.fightjava.com/web/index/course/detail/5

3、关注一下Debug的技术微信公众号呗,最新的技术文章、技术课程以及技术专栏将会第一时间在公众号发布哦!

推荐阅读:

SpringBoot系列(一):如何构建一个标准的Spring Boot项目

SpringBoot系列(二):如何构建统一的消息响应模型

SpringBoot系列(三):不要告诉我你还不会使用IDEA热部署功能

SpringBoot系列(四):SpringBoot整合Mybatis实现不一样的CRUD

SpringBoot系列(五):SpringBoot整合Mybatis实现多表关联查询

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表