浅谈guava包下Lists.newArrayListWithExpectedSize()的使用

目前app的代码中不少使用Lists.newArrayListWithExpectedSize(), 针对此方法的使用是否规范做了一些分析

 

1. 关于 Maps.newHashMapWithExpectedSize()

看到Lists.newArrayListWithExpectedSize()此方法, 想必你定会想到HashMap的Maps.newHashMapWithExpectedSize()方法,

 

我们知道HashMap的默认加载因子是0.75, HashMap在put新数据时, 会计算当前元素个数是否超过当前容量的0.75倍, 若达到则扩容。

 

在初始化HashMap时, 若使用者已知道具体的元素个数, 则初始化的HashMap的容量应该是

初始容量 = 元素个数/0.75 + 1

Maps.newHashMapWithExpectedSize()方法的存在就是帮助使用者做了计算这一步

我们来看下源码:

static int capacity(int expectedSize) {

if (expectedSize < 3) {

checkNonnegative(expectedSize, "expectedSize");

return expectedSize + 1;

}

if (expectedSize < Ints.MAX_POWER_OF_TWO) {

// This is the calculation used in JDK8 to resize when a putAll

// happens; it seems to be the most conservative calculation we

// can make. 0.75 is the default load factor.

return (int) ((float) expectedSize / 0.75F + 1.0F);

}

return Integer.MAX_VALUE; // any large value

}

 

 

2. ArrayList的扩容机制

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

//minCapacity为add后的元素个数

if (minCapacity - elementData.length > 0) {

//扩容操作

grow(minCapacity);

}

}

 

通过源码可见ArrayList的扩容机制与HashMap并不一样, ArrayList的在执行add方法时, 只有新增元素后的总长度大于容量时才进行扩容, 否则不扩容

 

具体扩容步骤如下

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1);

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// minCapacity is usually close to size, so this is a win:

elementData = Arrays.copyOf(elementData, newCapacity);

}

通过上述源码可以看到, ArrayList进行扩容时, 先进性一次扩容, 扩容后的容量大小为

oldCapacity + oldCapacity >>1

即原容量的1.5倍, 若当前元素个数(minCapacity) 还大于扩容后容量, 则取minCapacity为最新容量大小, 然后进行数据copy

 

3. Lists.newArrayListWithExpectedSize()的实现

static int computeArrayListCapacity(int arraySize) {

checkNonnegative(arraySize, "arraySize");

return Ints.saturatedCast(5L + arraySize + (arraySize / 10));

}

 

源码可以看出, newArrayListWithExpectedSize()方法对ArrayList的初始化容量的计算是

最终容量 = 5+预期值+ 预期值/10

若你要使用一个长度为100的集合, 使用该方法会初始化一个容量为 5+100+10=115的集合

 

看一下此方法的注释:

This method will soon be deprecated. Even in the rare case

* that you do want some amount of padding, it's best if you choose your

* desired amount explicitly.

这种方法很快就会被弃用。即使在罕见的情况下

*你需要一些填充物,最好选择

*明确要求的数量。

注释中说明 构建ArrayList时最好直接传入元素, 或者明确你要的容器数量

 

对参数的解释为:

an estimate of the eventual {@link List#size()}

对新列表的最终长度的估计值

 

也就是说, 当前方法是使用者不确定集合元素个数时, 但是有个预估值时去使用。

 

4. 目前代码中使用是否规范

目前代码中不少地方创建ArrayList是为了将一个实体类集合成为一个DTO集合的转换。也就是说是为了创建一个明确元素数量的ArrayList, 使用Lists.newArrayListWithExpectedSize() 则初始化的集合容量至少多出5, 造成了不必要的内存浪费

例如:

private List<ActivityInfoBo> getActiveBoList(List<Integer> activityIdList) {

List<ActivityInfoBo> activeList = Lists.newArrayListWithExpectedSize(activityIdList.size());

for (Integer activityId : activityIdList) {

ActivityInfoBo activityInfoBo = appConfig.getBrandWeekActivityBean()

.getActivityInfoByActivityId(activityId);

activeList.add(activityInfoBo);

}

return activeList;

}

 

当明确集合元素个数时, 初始化ArrayList可以使用ArrayList自带的构造函数

new ArrayList<>(n) n为集合长度值

或者使用Lists.newArrayListWithCapacity()方法, 此方法也是直接使用了ArrayList的构造

public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize) {

checkNonnegative(initialArraySize, "initialArraySize"); // for GWT.

return new ArrayList<E>(initialArraySize);

}

 

 

 

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值