Java8利用Stream对列表进行去除重复的方法详解


Posted in Java/Android onApril 14, 2022

一. Stream 的distinct()方法

distinct()是Java 8 中 Stream 提供的方法,返回的是由该流中不同元素组成的流。distinct()使用 hashCode() 和 eqauls() 方法来获取不同的元素。

因此,需要去重的类必须实现 hashCode() 和 equals() 方法。换句话讲,我们可以通过重写定制的 hashCode() 和 equals() 方法来达到某些特殊需求的去重。

distinct() 方法声明如下:

Stream<T> distinct();

1.1 对于 String 列表的去重

因为 String 类已经覆写了 equals() 和 hashCode() 方法,所以可以去重成功。

@Test
public void listDistinctByStreamDistinct() {
  // 1. 对于 String 列表去重
  List<String> stringList = new ArrayList<String>() {{
    add("A");
    add("A");
    add("B");
    add("B");
    add("C");
  }};
  out.print("去重前:");
  for (String s : stringList) {
    out.print(s);
  }
  out.println();
  stringList = stringList.stream().distinct().collect(Collectors.toList());
  out.print("去重后:");
  for (String s : stringList) {
    out.print(s);
  }
  out.println();

}

结果如下:

去重前:AABBC
去重后:ABC

1.2 对于实体类列表的去重

注:代码中我们使用了 Lombok 插件的 @Data注解,可自动覆写 equals() 以及 hashCode() 方法。

/**
* 定义一个实体类
*/  
@Data
public class Student {
  private String stuNo;
  private String name;
}
@Test
public void listDistinctByStreamDistinct() throws JsonProcessingException {
    ObjectMapper objectMapper = new ObjectMapper();
    // 1. 对于 Student 列表去重
    List<Student> studentList = getStudentList();
    out.print("去重前:");
    out.println(objectMapper.writeValueAsString(studentList));
    studentList = studentList.stream().distinct().collect(Collectors.toList());
    out.print("去重后:");
    out.println(objectMapper.writeValueAsString(studentList));
  }

结果如下:

去重前:[{"stuNo":"001","name":"Tom"},{"stuNo":"002","name":"Mike"},{"stuNo":"001","name":"Tom"}]
去重后:[{"stuNo":"001","name":"Tom"},{"stuNo":"002","name":"Mike"}]

二. 根据 List<Object> 中 Object 某个属性去重

2.1 新建一个列表出来

@Test
  public void distinctByProperty1() throws JsonProcessingException {
    // 这里第一种方法我们通过新创建一个只有不同元素列表来实现根据对象某个属性去重
    ObjectMapper objectMapper = new ObjectMapper();
    List<Student> studentList = getStudentList();
    out.print("去重前        :");
    out.println(objectMapper.writeValueAsString(studentList));
    studentList = studentList.stream().distinct().collect(Collectors.toList());
    out.print("distinct去重后:");
    out.println(objectMapper.writeValueAsString(studentList));
    // 这里我们引入了两个静态方法,以及通过 TreeSet<> 来达到获取不同元素的效果
    // 1. import static java.util.stream.Collectors.collectingAndThen;
    // 2. import static java.util.stream.Collectors.toCollection;
    studentList = studentList.stream().collect(
      collectingAndThen(
        toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName))), ArrayList::new)
    );
    out.print("根据名字去重后 :");
    out.println(objectMapper.writeValueAsString(studentList));
  }

结果如下:

去重前        :[{"stuNo":"001","name":"Tom"},{"stuNo":"001","name":"Tom"},{"stuNo":"003","name":"Tom"}]
distinct去重后:[{"stuNo":"001","name":"Tom"},{"stuNo":"003","name":"Tom"}]
根据名字去重后 :[{"stuNo":"001","name":"Tom"}]

2.2 通过 filter() 方法

我们首先创建一个方法作为 Stream.filter() 的参数,其返回类型为 Predicate,原理就是判断一个元素能否加入到 Set 中去,代码如下:

private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

使用如下:

@Test
  public void distinctByProperty2() throws JsonProcessingException {
    // 这里第二种方法我们通过过滤来实现根据对象某个属性去重
    ObjectMapper objectMapper = new ObjectMapper();
    List<Student> studentList = getStudentList();
    out.print("去重前        :");
    out.println(objectMapper.writeValueAsString(studentList));
    studentList = studentList.stream().distinct().collect(Collectors.toList());
    out.print("distinct去重后:");
    out.println(objectMapper.writeValueAsString(studentList));
    // 这里我们将 distinctByKey() 方法作为 filter() 的参数,过滤掉那些不能加入到 set 的元素
    studentList = studentList.stream().filter(distinctByKey(Student::getName)).collect(Collectors.toList());
    out.print("根据名字去重后 :");
    out.println(objectMapper.writeValueAsString(studentList));
  }

结果如下:

去重前        :[{"stuNo":"001","name":"Tom"},{"stuNo":"001","name":"Tom"},{"stuNo":"003","name":"Tom"}]
distinct去重后:[{"stuNo":"001","name":"Tom"},{"stuNo":"003","name":"Tom"}]
根据名字去重后 :[{"stuNo":"001","name":"Tom"}]

到此这篇关于Java8利用Stream实现列表去重的方法详解的文章就介绍到这了!

Java/Android 相关文章推荐
为什么在foreach循环中JAVA集合不能添加或删除元素
Jun 11 Java/Android
ConstraintValidator类如何实现自定义注解校验前端传参
Jun 18 Java/Android
mybatis 解决从列名到属性名的自动映射失败问题
Jun 30 Java/Android
Spring实现内置监听器
Jul 09 Java/Android
java解析XML详解
Jul 09 Java/Android
SSM项目使用拦截器实现登录验证功能
Jan 22 Java/Android
Java9新特性对HTTP2协议支持与非阻塞HTTP API
Mar 16 Java/Android
使用Java去实现超市会员管理系统
Mar 18 Java/Android
Java处理延时任务的常用几种解决方案
Jun 01 Java/Android
Java中生成微信小程序太阳码的实现方案
Jun 01 Java/Android
Springboot中如何自动转JSON输出
Jun 16 Java/Android
Android Gradle 插件自定义Plugin实现注意事项
Jun 16 Java/Android
详解Flutter网络请求Dio库的使用及封装
Apr 14 #Java/Android
详细介绍Java中的CyclicBarrier
Apr 13 #Java/Android
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
Apr 13 #Java/Android
Java的Object类的九种方法
Apr 13 #Java/Android
Java 使用类型为Object的变量指向任意类型的对象
Apr 13 #Java/Android
java中为什么说子类的构造方法默认访问的是父类的无参构造方法
Apr 13 #Java/Android
Spring Cloud Netflix 套件中的负载均衡组件 Ribbon
Apr 13 #Java/Android
You might like
php实现aes加密类分享
2014/02/16 PHP
PHP常见数组排序方法小结
2018/08/20 PHP
PHP封装的page分页类定义与用法完整示例
2018/12/24 PHP
Laravel 读取 config 下的数据方法
2019/10/13 PHP
Highslide.js是一款基于js实现的网页中图片展示插件
2020/03/30 Javascript
Mootools 1.2 手风琴(Accordion)教程
2009/09/15 Javascript
回车直接实现点击某按钮的效果即触发单击事件
2014/02/27 Javascript
函数式 JavaScript(一)简介
2014/07/07 Javascript
js实现从右向左缓缓浮出网页浮动层广告的方法
2015/05/09 Javascript
JavaScript电子时钟倒计时
2016/01/09 Javascript
字符串反转_JavaScript
2016/04/28 Javascript
jQuery中JSONP的两种实现方式详解
2016/09/26 Javascript
JavaScript调试的多个必备小Tips
2017/01/15 Javascript
javascript高级模块化require.js的具体使用方法
2017/10/31 Javascript
原生JS实现的多个彩色小球跟随鼠标移动动画效果示例
2018/02/01 Javascript
js定义类的方法示例【ES5与ES6】
2019/07/30 Javascript
微信小程序之数据绑定原理解析
2019/08/14 Javascript
npm 语义版本控制详解
2019/09/10 Javascript
移动端JS实现拖拽两种方法解析
2020/10/12 Javascript
Python Queue模块详解
2014/11/30 Python
python中的闭包用法实例详解
2015/05/05 Python
详解Python字典的操作
2019/03/04 Python
python opencv 二值化 计算白色像素点的实例
2019/07/03 Python
详解python中*号的用法
2019/10/21 Python
pyMySQL SQL语句传参问题,单个参数或多个参数说明
2020/06/06 Python
css3实现信纸/同学录效果的示例代码
2018/12/11 HTML / CSS
NFL Game Pass欧洲:在线观看NFL比赛直播和点播,以高清质量播放
2018/08/30 全球购物
aden + anais英国官网:美国婴儿贴身用品品牌
2019/09/08 全球购物
销售副总经理岗位职责
2013/12/11 职场文书
五五普法心得体会
2014/09/04 职场文书
高校师德师风自我剖析材料
2014/09/29 职场文书
教师批评与自我批评范文
2014/10/15 职场文书
2014年电厂工作总结
2014/12/04 职场文书
2015年销售部工作总结范文
2015/04/27 职场文书
2015年全国爱眼日活动方案
2015/05/05 职场文书
关于CSS浮动与取消浮动的问题
2021/06/28 HTML / CSS