Java8如何通过Stream对list对象某个属性去重

2026-07-07 303136 代码

学会Java8 Stream与TreeSet高效List去重!本文详解对象整体去重、单属性及多属性去重实战代码,直接复制即可用,点击立即掌握集合去重技巧,提升开发效率

目录
  • 前言
  • 正文
    • 数据对象
    • 1. 对象整体去重
    • 2. 单个属性去重(只返回属性)
    • 3. 单个属性去重
    • 4. 多个属性去重
    • 验证方法
    • 运行结果
  • 结尾

    前言

    对于list集合进行去重操作,多种情况进行记录.

    只记录在学习与实践过程中需要对集合操作的场景,方便下次能够直接快速的回忆起来.

    当然这些方法的使用与操作皆是对于Java8stream操作,TreeSet不重复特性进行的运用.

    如果能够更好更快的达成目的,也是不必拘泥于某一些固定的方式去处理数据,以效率与程序开销优先.

    正文

    数据对象

    将数据对象写成静态不可变的list来方便我们对于程序进行调用验证

    private static final List list = asList(
            new SyncBalance(BigDecimal.ZERO, "12345678", 0, 1, "GGBond", 32, 0),
            new SyncBalance(BigDecimal.ZERO, "22345678", 0, 1, "GGBond", 32, 0),
            new SyncBalance(BigDecimal.ZERO, "22345678", 1, 1, "GGBond", 32, 0),
            new SyncBalance(BigDecimal.ZERO, "22345678", 1, 1, "GGBond", 32, 0)
    );
    

    1. 对象整体去重

    /**
     * 1. 对所有属性一样的数据进行去重
     */
    public static void allColumnDistinct() {
        List allColumnDistinct = list.stream().distinct().collect(Collectors.toList());
    }
    

    2. 单个属性去重(只返回属性)

    /**
     * 2. 对单个属性去重,只返回去重的属性
     */
    public static void columnDistinct() {
        List columnDistinct = list.stream().map(SyncBalance::getMobile).distinct().collect(Collectors.toList());
    }
    

    3. 单个属性去重

    /**
     * 3-1. 对单个属性一样的数据进行去重,下面是对`mobile`去重
     */
    public static void oneColumnDistinctMethodOne() {
        List oneColumnDistinctMethodOne = list.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet(
                        Comparator.comparing(SyncBalance::getMobile))), ArrayList::new));
    }
    
    /**
     * 3-2. 对单个属性一样的数据进行去重,下面是对`mobile`去重(通过自定义属性去重方法)
     */
    public static void oneColumnDistinctMethodTwo() {
        List oneColumnDistinctMethodTwo = list.stream().filter(distinctByKey(i -> i.getMobile())).collect(Collectors.toList());
    }
    
    /**
    * list对象单个个字段去重(自定义属性)
    * @param keyExtractor 去重的对象字段
    * @return
    * @param 
    */
    public static  Predicate distinctByKey(Function keyExtractor) {
        Map seen = new ConcurrentHashMap();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
    
    
    /**
     * 3-3. 对单个属性一样的数据进行去重,下面是对`mobile`去重
     * 利用TreeSet进行去重
     */
    public static void oneColumnDistinctMethodThree() {
        TreeSet oneColumnDistinctMethodThree = new TreeSet(Comparator.comparing(i -> i.getMobile()));
        list.forEach(a -> oneColumnDistinctMethodThree.add(a));
    }
    

    4. 多个属性去重

    /**
     * 4. 多个字段条件去重
     */
    public static void twoColumnDistinct() {
        List twoColumnDistinct = list.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet(
                        Comparator.comparing(p -> p.getMobile() + ";" + p.getStatus()))), ArrayList::new));
    }
    

    验证方法

    对于验证方法添加了一些分隔的数据

    /**
     * 验证的main方法
     * @param args
     */
    public static void main(String[] args) {
        allColumnDistinct();
        columnDistinct();
        oneColumnDistinctMethodOne();
        oneColumnDistinctMethodTwo();
        oneColumnDistinctMethodThree();
        twoColumnDistinct();
    }
    

    运行结果

    allColumnDistinct---v
    SyncBalance(accountBalance=0, mobile=12345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=1, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    allColumnDistinct---^
    columnDistinct---v
    12345678
    22345678
    columnDistinct---^
    oneColumnDistinctMethodOne---v
    SyncBalance(accountBalance=0, mobile=12345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    oneColumnDistinctMethodOne---^
    oneColumnDistinctMethodTwo---v
    SyncBalance(accountBalance=0, mobile=12345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    oneColumnDistinctMethodTwo---^
    oneColumnDistinctMethodThree---v
    SyncBalance(accountBalance=0, mobile=12345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    oneColumnDistinctMethodThree---^
    twoColumnDistinct---v
    SyncBalance(accountBalance=0, mobile=12345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=0, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    SyncBalance(accountBalance=0, mobile=22345678, status=1, sysId=1, loginAccountName=GGBond, keepOrUpdate=32, id=0)
    twoColumnDistinct---^​

    结尾

    集合的操作不止拘泥于stream流TreeSet可以处理,其他一下如果可以实现皆可使用.

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

    您可能感兴趣的文章:

    • Java8 Stream API中实现集合list转map的多种方式
    • Java8使用Stream流实现List列表查询、统计、排序以及分组
    • java8 Stream大数据量List分批处理切割方式
    • Java8-Stream流操作List去重问题
    • java8如何用Stream查List对象某属性是否有重复
    • Java8 中使用Stream 让List 转 Map使用问题小结

    papi酱首谈原生家庭:父亲再婚对象仅比自己大几岁

      近日,网红博主papi酱在一档窦文涛主持的访谈节目《自然光》中罕见完整分享了原生家庭成长经历。节目中,她平静讲述父母常年争吵、父亲再婚、家庭债务等过往,相关话题#papi酱父亲再婚妻子仅比她大几岁#迅速登上热搜。   访谈现场,papi酱坦言父母早年长期持续争吵,相比最终离婚,无休止的家庭矛盾才是童年最大的心理负担。她形容父亲是典型的"至死是少年"式文人,早年从事记者工作,有才华、对她十分疼爱...

    盖洛普最新研究:不经常使用 AI 的员工更容易成为被裁员对象

    就爱读6月18日消息,据彭博社18日(今天)报道,盖洛普最新研究显示,AI给科技从业者带来的可能不只是效率提升,经常使用AI的员工,被裁员的风险也明显更低。就爱读从数据中获悉,在美国科技行业,每月至少使用一次AI的员工,预计遭裁员的概率约为6%;使用AI较少的员工,预计遭裁员的概率达到18%,是前者的三倍。研究数据来自盖洛普今年2月对超过2.3万名美国劳动者开展的调查,其中660人表示,自己的岗位...

    一文详解Python属性查找

    在 Python 面向对象编程的世界里,类属性与实例属性是构建程序的基石,而它们的查找顺序(MRO) 更是决定代码行为的核心逻辑,今天,我们就从基础概念到底层算法,彻底吃透 Python 属性查找的奥秘,需要的朋友可以参考下 目录引言一、先搞懂:类属性VS实例属性1.核心概念2.直观代码演示二、关键规则:属性查找「由下而上」三、进阶难点:多继承与MRO算法演变1.初代:深度优先搜索(Python2...

    C#代码实现读取或删除Excel文档属性

    Excel 文档属性(也称为元数据)能够提供有关文件内容、作者以及创建和修改历史等信息,本文主要介绍了如何使用C#代码实现读取或删除Excel文档属性,文中的示例代码讲解详细,有需要的可以了解下 目录安装Excel处理库在C#中读取Excel的标准文档属性和自定义文档属性在C#中删除Excel的标准文档属性和自定义文档属性知识扩展总结Excel文档属性(也称为元数据)能够提供有关文件内容、作者以及...

    Java synchronized关键字从字节码到对象头与锁升级(最新整理)

    susersynchronized底层原理详解,涉及Monitor、MarkWord、偏向锁与轻量级锁等机制,synchronized底层原理涉及Monitor实现、MarkWord结构、偏向锁及轻量级锁机制,深入剖析JVM层面与硬件层面实现细节 目录synchronized底层原理(总结版)synchronized底层原理(详解版)1.字节码层面:monitorenter和monitorexit...

    C#之List移除某个属性值中最大的值方式

    这段个方法教你如何在C#中移除ListListList中属性值最大的大的元素,涵盖.NET6的MaxBy、MaxFirst/与RemoveAll等种实现方式,助你高效管理列表数据 目录方法一:使用MaxBy(推荐,.NET6+)方法二:使用Max+First/FirstOrDefault(兼容旧版本)方法三:使用RemoveAll(移除所有最大值)注意事项总结 在C#中移除List中某个属性值最大...

    C#使用linq给List某个属性值赋值方式

    在C#中使用LINQ进行数据查询与修改的最佳实践,推荐使用ForEach方法或传统的foreach循环进行List对象属性赋值;避免直接在LINQ查询表达式中执行赋值操作;可考虑使用Select投影生成新列表以保持数据不变性 目录1.使用ForEach方法(推荐,简洁直观)2.使用传统foreach循环(性能最佳,标准做法)3.使用LINQSelect投影生成新列表(不可变风格)4.两个List关...

    Python中可变对象与不可变对象详细教程

    Python中,可变数据类型指的是数据值可以改变的数据类型,而不可变数据类型指的是数据值不可改变的数据类型,这篇文章主要介绍了Python中可变对象与不可变对象的相关资料,需要的朋友可以参考下 目录前言核心定义1.常见的不可变对象2.常见的可变对象3.为什么这个区别很重要?a)变量赋值和引用b)函数参数的传递c)作为字典的键4.特殊情况:元组中包含可变对象总结前言 我们来深入解析Python中一个...