首页 > 其他分享 >ArrayList的contains()方法的性能问题及优化方法

ArrayList的contains()方法的性能问题及优化方法

时间:2023-11-29 12:05:41浏览次数:27  
标签:HashMap HashSet ArrayList contains System 方法

背景

今天定位一个接口耗时问题,通过日志定位到在数据库查询完毕后,中间一段逻辑耗时很长有十几秒的样子,发现是循环中使用ArraysList中的contains方法,当循环数量级变得很大时,执行时间变得不可控。

代码示例

// 有5万个门店
        List<Store> storeList = storeMapper.selectAll();

        // 有十万个用户
        List<User> userList = userMapper.selectAll();

        // 最坏情况循环5亿次
        for (user : userList){
            if (storeList.contains(user.getStoreCode())){
                doSth();
            }
        }

1. 原理说明

1.1 ArrayList

ArrayList中contains()方法的实现过程:

ArrayList的contains()方法的性能问题及优化方法_System

contains()方法调用了indexOf()方法,indexOf()具体实现如下。从源码可以看出,该方法通过遍历数据和比较元素的方式来判断是否存在给定元素。当ArrayList中存放的元素非常多时,这种实现方式来判断效率将非常低,后面通过实例来验证。

ArrayList的contains()方法的性能问题及优化方法_System_02

 1.2 HashSet

既然ArrayList的contains()方法存在性能问题,那么就应该寻找改进的办法。这里推荐使用HashSet来代替ArrayList。
下面介绍HashSet的contains()方法的实现过程: 

HashSet将元素存放在HashMap中(HashMap的key)

ArrayList的contains()方法的性能问题及优化方法_i++_03

contains()方法调用HashMap的containsKey()方法

ArrayList的contains()方法的性能问题及优化方法_i++_04

containsKey()方法调用getEntry()方法。在该方法中,首先根据key计算hash值,然后从HashMap中取出该hash值对应的链表(链表的元素个数将很少),再通过变量该链表判断是否存在给定值。这种实现方式效率将比ArrayList的实现方法效率高非常多。

ArrayList的contains()方法的性能问题及优化方法_i++_05

2. 实例验证

2.1 测试ArrayList

public static void main(String[] args) {
	ArrayList<String> arrayList = new ArrayList<>();
	// 存入100000个数据
	for (int i = 0; i < 100000; i++) {
		arrayList.add("test" + i);
	}
		
	// 验证300000个数据(其中200000不存在)		
	long beginTime = System.currentTimeMillis();		for (int i = 0; i < 300000; i++) {
		arrayList.contains("test" + i);
	}
	long endTime = System.currentTimeMillis();
		
	System.out.println("cost time: " + (endTime - beginTime) + "ms");
}
打印结果:
cost time: 182210ms

 2.2 测试HashSet

public static void main(String[] args) {
		
	Set<String> hashSet = new HashSet<>();
	// 存入100000个数据
	for (int i = 0; i < 100000; i++) {
		hashSet.add("test" + i);
	}
		
	// 验证300000个数据(其中200000不存在)
	long beginTime = System.currentTimeMillis();
	for (int i = 0; i < 300000; i++) {
		hashSet.contains("test" + i);
	}
	long endTime = System.currentTimeMillis();
	
	System.out.println("cost time: " + (endTime - beginTime) + "ms");
}
打印结果:
cost time: 49ms

 3. 总结

通过第二节的实例可以看出,使用ArrayList的contains()耗时是使用HashSet的contains()方法的30多倍。具体原因可以参考第一节中的原理分析。

 

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。



ArrayList的contains()方法的性能问题及优化方法_i++_06

作者:翎野君


标签:HashMap,HashSet,ArrayList,contains,System,方法
From: https://blog.51cto.com/lingyejun/8613659

相关文章

  • url特殊字符传递参数解决方法(特指超链接)
    需要进行转码:十六进制值1.+URL中+号表示空格%2B2.空格URL中的空格可以用+号或者编码%203./分隔目录和子目录%2F4.?分隔实际的URL和参数%3F5.%指定特殊字符%256.#表示书签%237.&URL中指定的参数间的分隔符%268.=URL中指定参数的值%3D//带有特殊字符的......
  • js 拼接字符串带变量(js方法参数单双引号拼接的问题记录)
    小结:外面单引号,里面双引号,然后方法参数给转义的单引号即可(看下面的onClick事件即可)//刷新二级信号表格(增删改操作后)functionreloadSignal(subId){//清空$("#msgAll"+subId).empty();//js手工添加表格varhtmlStart='<spanstyle="position:......
  • numpy 普通方法
     ndarray.ndim-数组的维度:importnumpyasnp#创建一个一维数组arr_1d=np.array([1,2,3])print("数组:",arr_1d)print("数组的维度:",arr_1d.ndim)数组:[123]数组的维度:1ndarray.shape-数组的形状(维度大小):importnumpyasnp#创建一个二......
  • numpy 统计方法
      numpy.mean()importnumpyasnpa=np.array([[1,2,3],[3,4,5],[4,5,6]])print(a)print(np.mean(a))print(np.mean(a,axis=0))print(np.mean(a,axis=1))[[123][345][456]]3.6666666666666665[2.666666673.666666674.66666667][2.4.5.]......
  • Python自动化办公——3个Excel表格中每个门店物品不同,想要汇总在一起(方法五)
    大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Python自动化办公处理的问题,一起来看看吧。上一篇文章中,我们已经看到了四种解决办法了,这一篇文章我们一起来看看另外一种方法。二、实现过程这里【论草莓如何成为冻干莓】给了unstack()操作的方法,代码如下......
  • linux查看进程的基本方法
    要在Linux中查看进程,可以使用以下基本方法:1. **top命令:** 在终端中输入`top`,可以查看运行中的进程列表,以及它们的资源使用情况,如CPU和内存。2. **ps命令:** 使用`ps`命令可以列出当前用户的进程。例如,`ps aux`将显示所有用户的详细进程列表。3. **htop命令:** 这是top命令的......
  • JAVA判断图片真实格式的方法
    判断图片真实格式的方法,文件格式不是看后缀名,而是看文件头的定义publicclassImgUtil{publicstaticStringimgType(InputStreaminputStream)throwsIOException{//读取文件前几位byte[]fileHeader=newbyte[4];intread=inputStr......
  • Linux 中获取文件完整路径的4种方法介绍
    我们都知道,在命令行可以使用pwd命令来获取当前目录的完整路径(绝对路径):pwd那么,如何获取文件的绝对路径呢?有下列几种方法,可以打印文件的完整路径:readlinkrealpathfindls和pwd组合使用$readlink-fsample.txt/home/gliu/sample.txt$realpath-ssample.txt/home/gliu/samp......
  • 学到一个可以存储账号密码的方法
    //登录成功后,将用户名存储在HttpSession中HttpSessionsession=request.getSession();session.setAttribute("username",username);//假设这里的username是登录成功的用户名//在后续页面中获取保存在HttpSession中的用户名HttpSessionsession=request.getS......
  • 构造方法
    构造方法构造方法就是专门来创建对象的方法。当通过new关键字创建对象时,其实就是在调用构造方法。定义格式public构造方法名(参数类型参数名称){ 方法体 //return;通常省略不写}注意事项构造方法不能写返回值类型,连void都不能写。构造方法的名称必须和......