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

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

时间:2023-11-08 23:23:38浏览次数:42  
标签: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()方法的实现过程:

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

 1.2 HashSet

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

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

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

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

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多倍。具体原因可以参考第一节中的原理分析。

 

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

首发链接: https://www.cnblogs.com/lingyejun/p/17818584.html

标签:HashMap,HashSet,ArrayList,contains,System,方法
From: https://www.cnblogs.com/lingyejun/p/17818584.html

相关文章

  • springboot中部分数据的封装方法
    //响应字符串格式数据@RequestMapping("/hello")publicResulthello(){System.out.println("HelloWorld");//returnnewResult(1,"success","HelloWorld");returnResult.success("HelloWorl......
  • Java学习—Java方法
    那么什么是方法呢?Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的命名规则1.方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerso......
  • 在vue中页面跳转有几种方法?
    在Vue中,有几种方法可以实现页面跳转。以下是常用的几种方法:使用<router-link>组件:如果你使用了VueRouter来进行路由管理,可以使用<router-link>组件来创建带有路由的链接。例如:<router-linkto="/about">About</router-link>使用编程式导航:VueRouter还提供了编程式导航的......
  • Java 中时区转换的方法有哪些?
    1、使用java.util.TimeZone类进行时区转换。可以使用TimeZone类的静态方法获取某个时区的实例,例如TimeZone.getTimeZone("Asia/Shanghai"),然后使用SimpleDateFormat进行时间格式化,将时间从一个时区转换为另一个时区。示例代码:SimpleDateFormatformatter=newSimpleDateFo......
  • url特殊字符传递参数解决方法(特指超链接)
    需要进行转码:十六进制值1.+URL中+号表示空格%2B2.空格URL中的空格可以用+号或者编码%203./分隔目录和子目录%2F4.?分隔实际的URL和参数%3F5.%指定特殊字符%256.#表示书签%237.&URL中指定的参数间的分隔符%268.=URL中指定参数的值%3D//带有特殊字......
  • mybatis在xml文件中处理大于号小于号的方法
    第一种方法:用了转义字符把>和<替换掉,然后就没有问题了。SELECT*FROMtestWHERE1=1ANDstart_date <=CURRENT_DATEANDend_date>=CURRENT_DATE附:XML转义字符           <                     ......
  • 【U盘格式NTFS,FAT32,exFAT切换方法及各种文件系统区别】
    切换U盘格式步骤:1、格式化前,先确认把U盘离的数据进行备份,插入U盘,右击鼠标->点击格式化 2、进入格式化弹窗界面,选择所要修改的文件系统->点击开始->确定 各种文件系统区别:NTFS(NewTechnologyFileSystem意为新技术文件系统,其功能全面,应用最广泛。NTFS:1、NTFS这种格式的......
  • Promise.all静态方法
    前言AJAX的学习到这里就告一段落了,后面会做个小项目巩固之前学过的知识。后面会继续学习Node.js以及Git等知识。一、概念合并多个Promise对象,等待所有同时成功完成(或某一失败),做后续逻辑二、语法三、案例示例需求:同时请求“北京”,“上海”,“广州”,“深圳”的天气并在网页上尽可能同......
  • 白盒测试方法
    一、概述:白盒测试也称结构测试或逻辑驱动测试,是针对被测单元内部是如何进行工作的测试。它根据程序的控制结构设计测试用例,主要用于软件或程序验证。白盒测试法检查程序内部逻辑结构,对所有逻辑路径进行测试,是一种穷举路径的测试方法。但即使每条路径都测试过了,仍然可能存在错误......
  • Python处理日期方法大全、三十种方法
    一、使用time模块展示当前日期和时间importtimefromtimeimportgmtime,strftimet=time.localtime()print(time.asctime(t))#SunMay709:30:372017print(strftime("%a,%d%b%Y%H:%M:%S+0000",gmtime()))#Sun,07May201704:00:37+0000print(st......