Java8-Stream流操作List去重问题

目录
  • Java8Stream流操作List去重
  • List列表运用Java8的stream流按某字段去重
    • 问题
    • 思路

Java8Stream流操作List去重

根据属性去重整体去重使用

  • distinct
ArrayList<LabelInfoDTO> collect = labelInfoDTOS.stream().
collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LabelInfoDTO::getLabelCode))), ArrayList::new));

List列表运用Java8的stream流按某字段去重

问题

项目中经常会遇到列表去重的问题,一般可使用Java8的stream()流提供的distinct()方法:list.stream().distinct()。

list的类型为List<String>、List<Integer>,list里的元素为简单包装类型。

或者List<Xxx>,其中Xxx为自定义对象类型,重写equals和hashCode方法,可根据业务情况来实现,如id相同即认为对象相等。

有时会遇到这种情况,需要对按对象里的某字段来去重。

例如:

@NoArgsConstructor
@AllArgsConstructor
@Data
class Book {
 
    public static Book of(Long id, String name, String createTime) {
        return new Book(id, name, Date.from(LocalDateTime.parse(createTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).atZone(ZoneId.systemDefault()).toInstant()));
    }
 
    private Long id;
 
    private String name;
 
    private Date createTime;
}

现在我们要按name字段来去重,假设list如下:

List<Book> books = new ArrayList<>();
books.add(Book.of(1L, "Thinking in Java", "2021-06-29 17:13:14"));
books.add(Book.of(2L, "Hibernate in action", "2021-06-29 18:13:14"));
books.add(Book.of(3L, "Thinking in Java", "2021-06-29 19:13:14"));

思路

1、重写Book类的equals和hashCode方法,以name来判断比较是否相同,然后用stream的distinct方法来去重

代码:

class Book {
    ...
 
    @Override
    public String toString() {
        return String.format("(%s,%s,%s)", id, name, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return Objects.equals(name, book.name);
    }
}
 
List<Book> distinctNameBooks1 = books.stream().distinct().collect(Collectors.toList());
System.out.println(distinctNameBooks1);

总结:

通过重写equals和hashCode方法,按实际需求来比较,可直接使用stream的distinct方法去重,比较方便;

有时对象类不方便或者不能修改,如它已实现好或者是引用的三方包不能修改,该方法不能灵活地按字段来去重。

2、通过Collectors.collectingAndThen的Collectors.toCollection,里面用TreeSet在构造函数中指定字段

代码:

List<Book> distinctNameBooks2 = books.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName()))), ArrayList::new));
System.out.println(distinctNameBooks2);

总结:

使用stream流提供的方法,代码很简洁,但不足是虽然实现了去重效果,但list里的顺序变化了,而有的场景需要保持顺序。

3、通过stream的filter方法来去重,定义一个去重方法,参数为Function类型,返回值为Predicate类型

代码:

public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
    Map<Object, Boolean> map = new HashMap<>();
    return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
 
List<Book> distinctNameBooks3 = books.stream().filter(distinctByKey(o -> o.getName())).collect(Collectors.toList());
System.out.println(distinctNameBooks3);

总结:

通过封装定义一个去重方法,配合filter方法可灵活的按字段去重,保持了原列表的顺序,不足之处是内部定义了一个HashMap,有一定内存占用,并且多了一个方法定义。

4、通过stream的filter方法来去重,不定义去重方法,在外面创建HashMap

代码:

Map<Object, Boolean> map = new HashMap<>();
List<Book> distinctNameBooks4 = books.stream().filter(i -> map.putIfAbsent(i.getName(), Boolean.TRUE) == null).collect(Collectors.toList());
System.out.println(distinctNameBooks4);

总结:

仍然是配合filter方法实现去重,没有单独创建方法,临时定义一个HashMap,保持了原列表的顺序,不足之处是有一定内存占用。

PS:暂时没找到stream流原生支持的可按某字段去重并且保持原列表顺序的方法

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java8使用stream实现list中对象属性的合并(去重并求和)

    前言 需要对一个List中的对象进行唯一值属性去重,属性求和,对象假设为BillsNums,有id.nums.sums三个属性,其中id表示唯一值,需要nums与sums进行求和,并最后保持一份. 例如说:("s1", 1, 1),("s1",2,3),("s2",4,4), 求和并去重的话,就是("s1", 3, 4),("s2",4,4) 对象与属性 class BillsNums { private

  • java8如何用Stream查List对象某属性是否有重复

    目录 使用Stream查List对象某属性是否有重复 练习一下stream的一些用法 list的五种去重方式 方法一:使用java8新特性stream进行List去重 方法二:双重for循环去重 方法三:set集合判断去重,不打乱顺序 方法四:遍历后判断赋给另一个list集合 方法五:set和list转换去重 使用Stream查List对象某属性是否有重复 Java8开发中,针对List对象集合,常需要判断某个属性是否存在重复值.用Stream流处理能方便的得到结果. 练习一下stream的一些

  • Java 8 Stream.distinct() 列表去重的操作

    在这篇文章里,我们将提供Java8 Stream distinct()示例. distinct()返回由该流的不同元素组成的流.distinct()是Stream接口的方法. distinct()使用hashCode()和equals()方法来获取不同的元素.因此,我们的类必须实现hashCode()和equals()方法. 如果distinct()正在处理有序流,那么对于重复元素,将保留以遭遇顺序首先出现的元素,并且以这种方式选择不同元素是稳定的. 在无序流的情况下,不同元素的选择不一定是稳定

  • Java8 Stream中间操作实例解析

    这篇文章主要介绍了Java8 Stream中间操作实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 介绍Stream Stream 使用一种类似用于SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象. Stream API可以极大提高Java程序员的生产力,让程序员写出高效率.干净.简洁的代码. 这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等

  • Java8-Stream流操作List去重问题

    目录 Java8Stream流操作List去重 List列表运用Java8的stream流按某字段去重 问题 思路 Java8Stream流操作List去重 根据属性去重整体去重使用 distinct ArrayList<LabelInfoDTO> collect = labelInfoDTOS.stream(). collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(

  • Java8 stream流的map()方法你会使用了吗

    目录 一.前言 二.概述 三.详述 3.1.找出所有的学生姓名 3.2.将姓名为“赵三”的语文成绩置为90 3.3.找出一年级学生的成绩 四.总结 一.前言 在日常的开发工作中经常碰到要处理list中数据的问题,比如从数据库中查出了很多学生,由于一些原因需要在内存中找出这些学生中的所有姓名,或者把名为“王五”的语文成绩暂时修改为“100”,这些问题怎么处理呐,之前我们想到的是遍历每个元素,然后取出来放到另外一个集合中,在java8中对集合可以进行流式操作使上面的处理更简洁.今天来看下map()方

  • Java8 Stream 流常用方法合集

    目录 一.概述 二.分类 三.具体用法 1. 流的常用创建方法 2. 流的中间操作 3. 流的终止操作 一.概述 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作.使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询.也可以使用 Stream API 来并行执行操作. 简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式. 特点: 不是数据结构,不会保存数据.

  • 使用Java8 Stream流的skip + limit实现批处理的方法

    为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream.Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggregate operation),或者大批量数据操作 (

  • java8 Stream流逐行处理文本文件

    本文中为大家介绍使用java8 Stream API逐行读取文件,以及根据某些条件过滤文件内容 1. Java 8逐行读取文件 在此示例中,我将按行读取文件内容并在控制台打印输出. Path filePath = Paths.get("c:/temp", "data.txt"); //try-with-resources语法,不用手动的编码关闭流 try (Stream<String> lines = Files.lines( filePath )) {

  • Java8 Stream流的常用方法汇总

    目录 1.快速创建List (1).new一个list,一个一个添加 (2).Stream流:创建动态list,可以添加元素 (3).如果创建一个固定长度的list,可以使用Arrays.asList(…args)直接返回一个list 2.取对象的某一列: (1).遍历 (2).Stream流:map 3.过滤,或者说是根据一个判断条件筛选出目标对象 (1).遍历加 if (2).Stream流:filter 4.分组 (1).遍历加 if (2).Stream流:groupingBy 5.求和

  • Java集合Stream流操作的基本使用教程分享

    目录 事前准备 Filter Sorted Map Match Count Reduce 总结 Java 中可以使用 java.util.Stream 对一个集合(实现了java.util.Collection接口的类)做各种操作,例如:求和.过滤.排序等等. 这些操作可能是中间操作——返回一个 Stream 流,或者是终端操作——返回一个结果. 流操作并不会影响原来的集合,可以简单认为,流操作是把集合中的一个元素逐个复制放到一个首尾相接的流动的水槽中. Stream 流支持同步执行,也支持并发

  • Java8 Stream流根据多个字段去重

    目录 Stream流根据多个字段去重 Stream多字段去重,去重求和 完整demo如下 启动主函数 Stream流根据多个字段去重 分组 list.stream().collect(Collectors.groupingBy(ClassEntity::getGrade)); java8有一个collectingAndThen可以根据多个字段去重 list.stream() .collect(Collectors.collectingAndThen(Collectors.toCollection

  • Java8 Stream流多字段求和、汇聚的实例

    目录 Stream流多字段求和.汇聚 实现方法 对象类型数据处理 Map类型数据处理 Stream分组求和使用笔记 分组求和使用 Stream流多字段求和.汇聚 实现方法 利用 Collectors.toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) keyMapper:代表你最终想要获得的Map<Key, Value> 的Key valueMapper:代表你最终想要获得的Map<K

随机推荐