设为首页 - 加入收藏 武汉站长网 (http://www.027zz.com)- 国内知名站长资讯网站,提供最新最全的站长资讯,创业经验,网站建设等!
热搜: 2019 支付 软件 支持
当前位置: 首页 > 综合聚焦 > 移动互联 > 评测 > 正文

常见的集合容器应当避免的坑

发布时间:2019-07-13 09:58 所属栏目:[评测] 来源:Java技术架构
导读:前言 前不久帮同事一起 review 一个 job 执行缓慢的问题时发现不少朋友在撸码实现功能时还是有需要细节不够注意,于是便有了这篇文章。 ArrayList 踩坑 首先大家看看这段代码有什么问题嘛? 其实在大部分情况下这都是没啥问题,无非就是循环的往 ArrayList

?前言

前不久帮同事一起 review 一个 job 执行缓慢的问题时发现不少朋友在撸码实现功能时还是有需要细节不够注意,于是便有了这篇文章。

ArrayList 踩坑

常见的集合容器应当避免的坑

首先大家看看这段代码有什么问题嘛?

其实在大部分情况下这都是没啥问题,无非就是循环的往 ArrayList 中写入365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版而已。

但在特殊情况下,比如这里的 getData() 返回365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版非常巨大时后续 temp.add(str) 就会有问题了。

比如我们在 review 代码时发现这里返回的365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版有时会高达 2000W,这时 ArrayList 写入的问题就凸显出来了。

填坑指南

大家都知道 ArrayList 是由数组实现,而365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版的长度有限;需要在合适的时机对数组扩容。

这里以插入到尾部为例 add(E e)。

常见的集合容器应当避免的坑

  1. ArrayList?temp?=?new?ArrayList<>(2)?;?
  2. temp.add("1");?
  3. temp.add("2");?
  4. temp.add("3");?

当我们初始化一个长度为 2 的 ArrayList ,并往里边写入三条365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版时 ArrayList 就得扩容了,也就是将之前的365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版复制一份到新的数组长度为 3 的数组中。

常见的集合容器应当避免的坑

之所以是 3 ,是因为新的长度=原有长度 * 1.5

通过源码我们可以得知 ArrayList 的默认长度为 10。

常见的集合容器应当避免的坑

image

常见的集合容器应当避免的坑

但其实并不是在初始化的时候就创建了 DEFAULT_CAPACITY = 10 的数组。

常见的集合容器应当避免的坑

而是在往里边 add 第一个365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版的时候会扩容到 10。

既然知道了默认的长度为 10 ,那说明后续一旦写入到第九个元素的时候就会扩容为 10*1.5 =15。

这一步为数组复制,也就是要重新开辟一块新的内存空间存放这 15 个数组。

一旦我们频繁且数量巨大的进行写入时就会导致许多的数组复制,这个效率是极低的。

但如果我们提前预知了可能会写入多少条365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版时就可以提前避免这个问题。

比如我们往里边写入 1000W 条365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版,在初始化的时候就给定数组长度与用默认 10 的长度之间性能是差距巨大的。

我用 JMH 基准测试验证如下:

常见的集合容器应当避免的坑

常见的集合容器应当避免的坑

常见的集合容器应当避免的坑

根据结果可以看出预设长度的效率会比用默认的效率高上很多(这里的 Score 指执行完函数所消耗的时间)。

所以这里强烈建议大家:在有大量365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版写入 ArrayList 时,一定要初始化指定长度。

再一个是一定要慎用 add(int index, E element) 向指定位置写入365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版。

常见的集合容器应当避免的坑

通过源码我们可以看出,每一次写入都会将 index 后的365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版往后移动一遍,其实本质也是要复制数组;

但区别于往常规的往数组尾部写入365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版,它每次都会进行数组复制,效率极低。

LinkedList

提到 ArrayList 就不得不聊下 LinkedList 这个孪生兄弟;虽说都是 List 的容器,但本质实现却完全不同。

常见的集合容器应当避免的坑

LinkedList 是由链表组成,每个节点又有头尾两个节点分别引用了前后两个节点;因此它也是一个双向链表。

所以理论上来说它的写入非常高效,将不会有 ArrayList 中效率极低的数组复制,每次只需要移动指针即可。

这里偷懒就不画图了,大家自行脑补下。

对比测试

坊间一直流传:

LinkedList 的写入效率高于 ArrayList,所以在写大于读的时候非常适用于 LinkedList 。

常见的集合容器应当避免的坑?

常见的集合容器应当避免的坑

这里测试看下结论是否符合;同样的也是对 LinkedList 写入 1000W 次365棋牌官方网版_www.365棋牌游戏下载_365棋牌2018新版,通过结果来看初始化数组长度的 ArrayList 效率明显是要高于 LinkedList 。

但这里的前提是要提前预设 ArrayList 的数组长度,避免数组扩容,这样 ArrayList 的写入效率是非常高的,而 LinkedList 的虽然不需要复制内存,但却需要创建对象,变换指针等操作。

而查询就不用多说了,ArrayList 可以支持下标随机访问,效率非常高。

【免责声明】本站内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。

网友评论
推荐文章