list集合常见去重方式以及效率对比

1.概述

list集合去重是开发中比较常用的操作,在面试中也会经常问到,那么list去重都有哪些方式?他们之间又该如何选择呢?

本文将通过LinkedHashSet、for循环、list流toSet、list流distinct等4种方式分别做1W数据到1000W数据单元测试,对比去重效率

2.代码实现

2.1准备工作

构建list集合,往里面插入数据,在插入几条重复数据,用jdk自带的System.currentTimeMillis()做计时器。

java 复制代码
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.stream.Collectors;

public class Test {

    public static void main(String[] args) {
        List<String> list1 = initList(10000);
        test(list1);
        List<String> list2 = initList(50000);
        test(list2);
        List<String> list3 = initList(100000);
        test1(list3);
        List<String> list4 = initList(500000);
        test1(list4);
        List<String> list5 = initList(1000000);
        test1(list5);
        List<String> list6 = initList(2000000);
        test1(list6);
        List<String> list7 = initList(3000000);
        test1(list7);
        List<String> list8 = initList(5000000);
        test1(list8);
        List<String> list9 = initList(10000000);
        test1(list9);
    }

    public static List<String> initList(int num){
        System.out.println("--------------------------");
        final List<String> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add("haha-"+ i);
        }
        list.add("haha-"+ 1000);
        list.add("haha-"+ 2000);
        list.add("haha-"+ 3000);
        System.out.println("list 初始化完毕 size = " + list.size());
        return list;
    }


    public static void test(List<String> list){
        long startLong = System.currentTimeMillis();
        List<String> list1 = removeDuplicate(list);
        System.out.println("去重后,集合元素个数 :" + list1.size());
        long endLong = System.currentTimeMillis();
        System.out.println("LinkedHashSet 测试完毕,实际耗时:"+ (endLong-startLong)  +" ,ms");

        long startLong1 = System.currentTimeMillis();
        List<String> list2 = removeDuplicate1(list);
        System.out.println("去重后,集合元素个数 :" + list2.size());
        long endLong1 = System.currentTimeMillis();
        System.out.println("for增强型循环 测试完毕,实际耗时:"+ (endLong1-startLong1)  +" ,ms");

        long startLong2 = System.currentTimeMillis();
        List<String> list3 = removeDuplicate2(list);
        System.out.println("去重后,集合元素个数 :" + list3.size());
        long endLong2 = System.currentTimeMillis();
        System.out.println("list流toSet方式 测试完毕,实际耗时:"+ (endLong2-startLong2)  +" ,ms");

        long startLong3 = System.currentTimeMillis();
        List<String> list4 = removeDuplicate3(list);
        System.out.println("去重后,集合元素个数 :" + list4.size());
        long endLong3 = System.currentTimeMillis();
        System.out.println("list流distinct方式 测试完毕,实际耗时:"+ (endLong3-startLong3)  +" ,ms");
        System.out.println("--------------------------");
    }

    public static void test1(List<String> list){
        long startLong = System.currentTimeMillis();
        List<String> list1 = removeDuplicate(list);
        System.out.println("去重后,集合元素个数 :" + list1.size());
        long endLong = System.currentTimeMillis();
        System.out.println("LinkedHashSet 测试完毕,实际耗时:"+ (endLong-startLong)  +" ,ms");

        long startLong2 = System.currentTimeMillis();
        List<String> list3 = removeDuplicate2(list);
        System.out.println("去重后,集合元素个数 :" + list3.size());
        long endLong2 = System.currentTimeMillis();
        System.out.println("list流toSet方式 测试完毕,实际耗时:"+ (endLong2-startLong2)  +" ,ms");

        long startLong3 = System.currentTimeMillis();
        List<String> list4 = removeDuplicate3(list);
        System.out.println("去重后,集合元素个数 :" + list4.size());
        long endLong3 = System.currentTimeMillis();
        System.out.println("list流distinct方式 测试完毕,实际耗时:"+ (endLong3-startLong3)  +" ,ms");
        System.out.println("--------------------------");
    }

    private static List<String> removeDuplicate(List<String> list) {
        return new ArrayList<>(new LinkedHashSet<>(list));
    }

    private static List<String> removeDuplicate1(List<String> list) {
        List<String> result = new ArrayList<String>(list.size());
        for (String str : list) {
            if (!result.contains(str)) {
                result.add(str);
            }
        }
        return result;
    }

    private static List<String> removeDuplicate2(List<String> list) {
        return list.stream().collect(Collectors.toSet()).stream().collect(Collectors.toList());
    }

    private static List<String> removeDuplicate3(List<String> list) {
        return  list.stream().distinct().collect(Collectors.toList());
    }

}

2.2输出结果

java 复制代码
--------------------------
list 初始化完毕 size = 10003
去重后,集合元素个数 :10000
LinkedHashSet 测试完毕,实际耗时:7 ,ms
去重后,集合元素个数 :10000
for增强型循环 测试完毕,实际耗时:342 ,ms
去重后,集合元素个数 :10000
list流toSet方式 测试完毕,实际耗时:89 ,ms
去重后,集合元素个数 :10000
list流distinct方式 测试完毕,实际耗时:5 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 50003
去重后,集合元素个数 :50000
LinkedHashSet 测试完毕,实际耗时:12 ,ms
去重后,集合元素个数 :50000
for增强型循环 测试完毕,实际耗时:6059 ,ms
去重后,集合元素个数 :50000
list流toSet方式 测试完毕,实际耗时:12 ,ms
去重后,集合元素个数 :50000
list流distinct方式 测试完毕,实际耗时:5 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 100003
去重后,集合元素个数 :100000
LinkedHashSet 测试完毕,实际耗时:14 ,ms
去重后,集合元素个数 :100000
list流toSet方式 测试完毕,实际耗时:13 ,ms
去重后,集合元素个数 :100000
list流distinct方式 测试完毕,实际耗时:13 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 500003
去重后,集合元素个数 :500000
LinkedHashSet 测试完毕,实际耗时:101 ,ms
去重后,集合元素个数 :500000
list流toSet方式 测试完毕,实际耗时:40 ,ms
去重后,集合元素个数 :500000
list流distinct方式 测试完毕,实际耗时:34 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 1000003
去重后,集合元素个数 :1000000
LinkedHashSet 测试完毕,实际耗时:75 ,ms
去重后,集合元素个数 :1000000
list流toSet方式 测试完毕,实际耗时:93 ,ms
去重后,集合元素个数 :1000000
list流distinct方式 测试完毕,实际耗时:162 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 2000003
去重后,集合元素个数 :2000000
LinkedHashSet 测试完毕,实际耗时:140 ,ms
去重后,集合元素个数 :2000000
list流toSet方式 测试完毕,实际耗时:2807 ,ms
去重后,集合元素个数 :2000000
list流distinct方式 测试完毕,实际耗时:231 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 3000003
去重后,集合元素个数 :3000000
LinkedHashSet 测试完毕,实际耗时:177 ,ms
去重后,集合元素个数 :3000000
list流toSet方式 测试完毕,实际耗时:654 ,ms
去重后,集合元素个数 :3000000
list流distinct方式 测试完毕,实际耗时:417 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 5000003
去重后,集合元素个数 :5000000
LinkedHashSet 测试完毕,实际耗时:307 ,ms
去重后,集合元素个数 :5000000
list流toSet方式 测试完毕,实际耗时:6364 ,ms
去重后,集合元素个数 :5000000
list流distinct方式 测试完毕,实际耗时:711 ,ms
--------------------------
--------------------------
list 初始化完毕 size = 10000003
去重后,集合元素个数 :10000000
LinkedHashSet 测试完毕,实际耗时:738 ,ms
去重后,集合元素个数 :10000000
list流toSet方式 测试完毕,实际耗时:1790 ,ms
去重后,集合元素个数 :10000000
list流distinct方式 测试完毕,实际耗时:1746 ,ms
--------------------------

3.总结

3.1 for循环方式去重(谨慎使用)

原因有2点:1.代码不简洁;2.耗时随着数据增大性能显著增高

3.2 LinkedHashSet(推荐)

LinkedHashSet是jdk自带的,所以jdk所有版本都支持使用,按照测试结果来说,对于方便和性能要求不那么极限的来说无脑使用LinkedHashSet是最方便的的。list流distinct在70w数据以下都会比LinkedHashSet效率高。

3.3 list流toSet(不推荐)

按照测试结果,list流的toSet方式在不同数据量的效率有很大的波动,且在任意测试节点都没有LinkedHashSet或者list流distinct效率高,所以也不推荐使用。

3.4 list流distinct(推荐)

list流是jdk8及以上提供的特性,在实际场景中,去重数据量超过10W基本没有,只要jdk支持list流那么使用list流distinct

综上:遵循jdk8以下用LinkedHashSet,jdk8及以上用list流distinct

相关推荐
whltaoin1 小时前
SpringCloud 项目阶段九:Kafka 接入实战指南 —— 从基础概念、安装配置到 Spring Boot 实战及高可用设计
spring boot·spring cloud·kafka
callJJ2 小时前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(2)
java·开发语言·后端·spring·ioc·di
wangjialelele2 小时前
Linux中的线程
java·linux·jvm·c++
谷咕咕2 小时前
windows下python3,LLaMA-Factory部署以及微调大模型,ollama运行对话,开放api,java,springboot项目调用
java·windows·语言模型·llama
没有bug.的程序员2 小时前
MVCC(多版本并发控制):InnoDB 高并发的核心技术
java·大数据·数据库·mysql·mvcc
在下村刘湘3 小时前
maven pom文件中<dependencyManagement><dependencies><dependency> 三者的区别
java·maven
不务专业的程序员--阿飞4 小时前
JVM无法分配内存
java·jvm·spring boot
李昊哲小课4 小时前
Maven 完整教程
java·maven
Lin_Aries_04214 小时前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc
脑花儿4 小时前
ABAP SMW0下载Excel模板并填充&&剪切板方式粘贴
java·前端·数据库