Java 你还在用lsit.contain做去重? 你是故意的还是不小心的?

前言

最近又是一轮代码review , 发现了一些实现去重的代码,在使用 lsit.contain ......

如:

我沉思,是不是其实很多初学者也存在这种去重使用问题?

所以我选择把这个事情整出来,分享一下。

正文


首先是造出一个 List<String> 模拟数据,一共2W条,里面有一半数据1W条是重复的:

    public static List<String> getTestList() {
        List<String> list = new ArrayList<>();
        for (int i = 1; i <= 10000; i++) {
            list.add(String.valueOf(i));
        }
        for (int i = 10000; i >= 1; i--) {
            list.add(String.valueOf(i));
        }
        return list;
    }

先看看 我们用contain 去重的 代码:

    /**
     * 使用 list.contain 去重
     *
     * @param testList
     */
    private static void useContain2Distinct(List<String> testList) {
        System.out.println("contains 开始去重,条数:" + testList.size());
        List<String> testListDistinctResult = new ArrayList<>();
        for (String str : testList) {
            if (!testListDistinctResult.contains(str)) {
                testListDistinctResult.add(str);
            }
        }
        System.out.println("contains 去重完毕,条数:" + testListDistinctResult.size());
    }

我们调用一下看看耗时:

    public static void main(String[] args) {
        List<String> testList = getTestList();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        useContainDistinct(testList);
        stopWatch.stop();
        System.out.println("去重 最终耗时" + stopWatch.getTotalTimeMillis());
    }

耗时:

 评价: list.contain 的效率,我的建议是,知道就行,别用。


众所周知Set 不存在 重复数据, 所以我们来看看 使用HashSet去重的性能:
ps: 这里是采取使用 set的add 方法做去重

    /**
     * 使用set去重
     *
     * @param testList
     */
    private static void useSetDistinct(List<String> testList) {
        System.out.println("HashSet.add 开始去重,条数:" + testList.size());
        List<String> testListDistinctResult = new ArrayList<>(new HashSet(testList));
        System.out.println("HashSet.add 去重完毕,条数:" + testListDistinctResult.size());
    }

我们调用一下看看耗时:

    public static void main(String[] args) {
        List<String> testList = getTestList();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        useSetDistinct(testList);
        stopWatch.stop();
        System.out.println("去重 最终耗时" + stopWatch.getTotalTimeMillis());
    }

耗时:


 

评价:HashSet 的效率,我的建议是,推荐。


 

为什么耗时 差距这么大?

不多说,我们看源码:

list.contains(o):

 可以看到里面用到了 index(o) :

时间复杂度 : O(n) n: 元素个数

那么我们看看 set.add(o) 是怎么样的 :

map的add , 老生常谈就不谈了,hash完 直接塞到某个位置, 时间复杂度 : O(1)  。

所以 O(n) 和  O(1) 谁快  谁慢 ? 显然。

 

ps: 顺嘴说下 hashset的 contain  

时间复杂度也是 : O(1)   

那么我们最后再看看别的去重:
 

双for循环 ,remove去重 

    /**
     * 使用双for循环去重
     * @param testList
     */
    private static void use2ForDistinct(List<String> testList) {
        System.out.println("list 双循环 开始去重,条数:" + testList.size());
        for (int i = 0; i < testList.size(); i++) {
            for (int j = i + 1; j < testList.size(); j++) {
                if (testList.get(i).equals(testList.get(j))) {
                    testList.remove(j);
                }
            }
        }
        System.out.println("list 双循环  去重完毕,条数:" + testList.size());
    }
    public static void main(String[] args) {
        List<String> testList = getTestList();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        use2ForDistinct(testList);
        stopWatch.stop();
        System.out.println("去重 最终耗时" + stopWatch.getTotalTimeMillis());
    }

耗时:

 评价:知道就行,图个乐,别用,贼慢,而且代码看起来乱:。


 

stream的distinct去重:
 

    /**
     * 使用Stream 去重
     *
     * @param testList
     */
    private static void useStreamDistinct(List<String> testList) {
        System.out.println("stream 开始去重,条数:" + testList.size());
        List<String> testListDistinctResult = testList.stream().distinct().collect(Collectors.toList());
        System.out.println("stream 去重完毕,条数:" + testListDistinctResult.size());
    }
    public static void main(String[] args) {
        List<String> testList = getTestList();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        useStreamDistinct(testList);
        stopWatch.stop();
        System.out.println("去重 最终耗时" + stopWatch.getTotalTimeMillis());
    }

耗时:

 

 评价:还不错,主要是代码也蛮简洁,有一点点动心。

好了,该篇就到这。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/6071.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux基础教程

Linux 目标 ​ Linux概述【了解】 ​ Linux网络连接三种模式【了解】 Linux目录结构【掌握】 Linux常用命令【掌握】 Linux操作目录的命令【掌握】 Linux操作文件的命令【掌握】 Linux的Vi编辑器【会用】 Linux打包与解压命令【掌握】 一、Linux概述 1、Linux的概述…

动力节点王鹤SpringBoot3学习笔记——第五章 说说Web服务

目录 第五章 说说Web服务 5.1 高效构建Web应用 5.1.1 html页面视图 5.1.2 JSON视图 5.1.3 给项目加favicon 5.2 Spring MVC 5.2.1 控制器Controller 5.2.1.1 匹配请求路径到控制器方法 5.2.1.2 RequestMapping 5.2.1.3 控制器方法参数类型与可用返回值类型 5…

HashMap底层数据结构

TreeMap TreeMap的底层是红黑树&#xff0c;是自平衡的二叉查找树。 在查找元素时会从左子树或右子树查找&#xff0c;和元素一个一个进行比较&#xff0c;对于大数量的查找的场景TreeMap不适合&#xff08;HashMap解决了这个问题&#xff09;。 TreeMap的好处&#xff0c;是…

隐私计算 FATE - 多分类神经网络算法测试

一、说明 本文分享基于 Fate 使用 横向联邦 神经网络算法 对 多分类 的数据进行 模型训练&#xff0c;并使用该模型对数据进行 多分类预测。 二分类算法&#xff1a;是指待预测的 label 标签的取值只有两种&#xff1b;直白来讲就是每个实例的可能类别只有两种 (0 或者 1)&…

两个数组的交集(力扣刷题)

给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/intersection-of-two-arrays 说…

人大女王金融硕士——站在一个更高的起点,拓宽自己的眼界

俗话说&#xff1a;“视野所及&#xff0c;心之所止”。做任何事情&#xff0c;最重要的是眼光。眼界不一样&#xff0c;就会有不一样的人生。站得更高才能看得更远&#xff0c;看得更远才能收获更多。人民大学与加拿大女王大学金融硕士项目为我们提供在职读研平台&#xff0c;…

Python机器学习:最大熵模型

信息论里&#xff0c;熵是可以度量随机变量的不确定性的&#xff0c;已经证明的&#xff1a;当随机变量呈均匀分布的时候&#xff0c;熵值最大&#xff0c;一个有序的系统有着较小的熵值&#xff0c;无序系统的熵值则较大。 机器学习里面&#xff0c;最大熵原理假设&#xff1…

【HAL库】HAL库STM32cubemx快速使用

文章目录整体框图一、基础工程1 新建工程2 配置RCC3 配置SYS4 工程设置5 生成代码6 keil设置下载&复位二、必备外设1 目录规范2 LED2 RTC3 USART4 KEY三、其他外设1 OLED&#xff08;模拟IIC、模拟SPI&#xff09;2 BH1750光强检测3 MQ2烟雾检测3 MQ4甲醛检测4 DHT11温湿度…

基于蓄电池进行调峰和频率调节研究【超线性增益的联合优化】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。⛳座右铭&#…

第04章_运算符

第04章_运算符 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目前在某公…

该不该放弃嵌入式,单片机这条路?

本文几乎浓缩了我从业10几年的精华&#xff0c;内容涵盖我转行、打工、创业的经历。 建议从头到尾不要错过一字一句&#xff0c;因为字里行间的经验之谈&#xff0c;或许能成为你人生重要转折点。 全文3700多字&#xff0c;写了6个多小时&#xff0c;如果你赶时间&#xff0c;建…

【17】核心易中期刊推荐——深度学习 | 遥感图像处理

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…

【学会这几个VSCode插件,让你的Python代码更优秀】

VSCode&#xff08;Visual Studio Code&#xff09;是由微软研发的一款免费、开源的跨平台文本&#xff08;代码&#xff09;编辑器&#xff0c;一般主要用于轻量级的编程代码工作&#xff0c;就非常适合Python&#xff0c;同时在前端开发方面也有举足轻重的地位。但如果想用于…

蓝桥杯集训·每日一题Week3

Trie AcWing 835. Trie字符串统计&#xff08;算法基础课&#xff09; 思路&#xff1a; Trie是一种高效地存储和查找字符串集合的数据结构,适用于字符串不太复杂的情况。其形状是一个以0为根节点的树&#xff0c;查询和插入的效率都比较高&#xff0c;有插入和查询两种操作。…

制造业的寒冬真的要来了吗?

制造业的寒冬真的要来了吗&#xff1f;其实当前&#xff0c;我国制造业发展水平是处于全球第三阵列&#xff0c;排名第四的&#xff1a; 但能处第三序列靠前&#xff0c;还是因为“规模发展”起了重要支撑——依靠规模拉动发展。所以如果从“质量效益”、“结构优化”、“持续发…

【AI探索】我问了ChatGPT几个终极问题

终于尝试了一把ChatGPT的强大之处&#xff0c;问了一下关心的几个问题&#xff1a; chatGPT现在在思考吗&#xff1f;有没有什么你感兴趣的问题&#xff1f; 你认为AI会对人类产生哪些方面的影响&#xff1f; 你对人类所涉及到的学科有了解吗&#xff1f;你认为在哪些方面与人类…

JetPack Compose之Modifier修饰符

前言 在Compose中&#xff0c;每一个组件都是带有Compose注解的函数&#xff0c;被称为Composable。Compose已经预置了很多的Compose UI组件&#xff0c;这些组件都是基于Material Design规范设计的&#xff0c;例如Button&#xff0c;TextField&#xff0c;TopAPPBar等。在布…

IOC、AOP、和javca面试题

一、 1、控制反转&#xff08;IOC&#xff09; 将创建管理对象的工作交给容器来做。在容器初始化&#xff08;或在某个时间节点&#xff09;通过反射机制创建好对象&#xff0c;在使用时直接从容器中获取。 控制反转&#xff1a;将对象的控制权反过来交给容器管理。 IOC实现…

既然有http 请求,为什么还要用rpc调用?

先弄明白什么是RPC。 RPC&#xff08;Remote Procedure Call&#xff09;—远程过程调用&#xff0c;它是一种通过网络从远程计算机程序上请求服务&#xff0c;而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在&#xff0c;如TCP或UDP&#xff0c;为通信程序之…

【面试】Java并发编程面试题

文章目录基础知识为什么要使用并发编程多线程应用场景并发编程有什么缺点并发编程三个必要因素是什么&#xff1f;在 Java 程序中怎么保证多线程的运行安全&#xff1f;并行和并发有什么区别&#xff1f;什么是多线程多线程的好处多线程的劣势&#xff1a;线程和进程区别什么是…