牛皮了!头一次见大佬把「Map遍历性能问题」详解得如此清晰明了
本文插图
我们知道java HashMap的扩容是有成本的 , 为了减少扩容的次数和成本 , 可以给HashMap设置初始容量大小 , 如下所示:
但是在实际使用的过程中 , 发现性能不但没有提升 , 反而显著下降了!代码里对HashMap的操作也只有遍历了 , 看来是遍历出了问题 , 于是做了一番测试 , 得到如下结果:
迭代器测试
贴上测试代码:
本文插图
本文插图
这是运行结果:
本文插图
我们将第一个Map初始化10w大小 , 第二个map不指定大小(实际16) , 两个存储相同的数据 , 但是用迭代器遍历100次的时候发现性能差异 , 一个36ms一个4ms , 实际上性能差距更大 , 这里的4ms是600次System.out.print的耗时 , 这里将print注掉再试下
输出结果如下:
本文插图
可以发现第二个map耗时几乎为0 , 第一个达到了28ms , 遍历期间没有进行任何操作 , 既然石锤了和 initial capacity 有关 , 下一步我们去看看为什么会这样 , 找找Map迭代器的源码看看 。
迭代器源码探究
我们来看看Map.entrySet.iterator的源码;
其中EntryIterator是HashMap的内部抽象类 , 源码并不多 , 我全部贴上来并附上中文注释
本文插图
本文插图
上面的代码一看就明白了 , 迭代器每次寻找下一个元素都会去遍历数组 , 如果 initial capacity 特别大的话 , 也就是说 threshold 也大 , table.length就大 , 所以遍历比较耗性能 。
table数组的大小设置是在resize方法里:
其他遍历方法
注意代码里我们用的是Map.entrySet.iterator , 实际上和keys.iterator, values.iterator 一样 , 源码如下:
本文插图
这两个就不分析了 , 性能一样 。
实际使用中对集合的遍历还有几种方法:
增强型for循环
增强行for循环实际上是通过迭代器来实现的 , 我们来看两者的联系
- 航天器|由于气候变暖,越来越多的信天翁“离婚”了
- |每小时收费500元?“女陪玩”出现天价,“灰色生意”该叫停了
- 火山喷发|西班牙火山喷发60天不停歇,生成千顷土地,地球“小冰期”来了?
- |“撒哈拉之眼”是亚特兰蒂斯遗迹?这些细节之处太相似了
- 登月|阿姆斯特朗勘探地下洞穴时,比登月还激动,因为发现了黄金天书?
- 太空|王亚平近照出现浮肿引发争议,真的是伙食太好了吗?真相让人心疼
- |脊椎动物一路向前,从此改变了我们的生物世界!
- 相机|了解眼睛有多神奇:人眼像素高达5.76亿,意味着什么?
- 汽车|手机已经容不下高通了
- 荣耀|荣耀60系列爆料汇总:外观、性能、拍照、续航基本都确认了