guava之Lists常用示例及newArrayListWithExpectedSize()和newArrayListWithCapacity()详细对比

时间:2022-07-01 20:49:10
谷歌提供了guava包里面有很多的工具类,现在先看Lists这个集合工具,对list集合操作做了些优化提升。

现提供如下使用实例。

package com.lxk.guavaTest;

import com.google.common.collect.Lists;

import java.util.List;

/**
* Created by lxk on 2016/11/7
*/
public class ListsTest {

public static void main(String[] args) {
testLists();
}

/**
* 测试 guava Lists
*/
private static void testLists() {

List<String> list1 = Lists.newArrayList();
for (int i = 0; i < 10; i++) {
list1.add(i + "");
}
System.out.println("list1: " + list1);
List<String> list2 = Lists.newArrayList("1", "2", "3");
System.out.println("list2: " + list2);
List<String> list3 = Lists.newArrayList(new String[]{"22", "22"});
System.out.println("list3: " + list3);
List<String> list4 = Lists.newArrayList(list1);
System.out.println("list4: " + list4);

//下面的这个写法呢是在初始化list的时候,说明容器的扩容界限值

//使用条件:你确定你的容器会装多少个,不确定就用一般形式的

//说明:这个容器超过10个还是会自动扩容的。不用担心容量不够用。默认是分配一个容量为10的数组,不够将扩容
//执行数组数据迁移操作:新建新数组,复制就数组数据到新数组(包括开辟新空间,copy数据等等,耗时,耗性能)

//对下数字10的说明:若直接new一个list的话,默认大小是10的数组,下面的方式则是 5L + x + x/10 = 16L(x = 10),在17的时候扩容

//整个来说的优点有:节约内存,节约时间,节约性能。代码质量提高。
List<String> list = Lists.newArrayListWithExpectedSize(10);

//这个方法就是直接返回一个10的数组。
List<String> list_ = Lists.newArrayListWithCapacity(10);
}
}


下面先是关于Lists.newArrayListWithExpectedSize(10)的源码简单分析

  @GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayListWithExpectedSize(int estimatedSize) {
return new ArrayList<E>(computeArrayListCapacity(estimatedSize));
}

static int computeArrayListCapacity(int arraySize) {
checkNonnegative(arraySize, "arraySize");

// TODO(kevinb): Figure out the right behavior, and document it
return Ints.saturatedCast(5L + arraySize + (arraySize / 10));
}
static int checkNonnegative(int value, String name) {
if (value < 0) {
throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
}
return value;
}
public static int saturatedCast(long value) {
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (value < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) value;
}

public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}

然后是Lists.newArrayListWithCapacity(10)的源码简单分析

  @GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize) {
checkNonnegative(initialArraySize, "initialArraySize"); // for GWT.
return new ArrayList<E>(initialArraySize);
}

然后看上面的主要是ArrayList,然后就看看ArrayList源码里面的add方法以及如何扩容的。

	/**
* list底层的用来保存数据的数组
*/
private transient Object[] elementData;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;

public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! (Increments 翻译-- 增量; 增长( increment的名词复数 ); 增额; 定期的加薪;)
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) { // Internal 翻译-- 内部的; 国内的; 体内的; 内心的; Capacity 翻译-- 容量; 性能; 才能; 生产能力;
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}

ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) { //Explicit 翻译-- 明确的,清楚的; 直言的; 详述的; 不隐瞒的;
modCount++;

// overflow-conscious code
if (minCapacity - elementData.length > 0) // 扩容条件,就是minCapacity = size + 1 大于当前数组的长度。就扩容。
grow(minCapacity);
}

private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //新容量相当于是原来容量的1.5倍(old + old>>1右移一位即除以2)
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 的modCount属性,java源码里面写的注释很长一大串,不是一时半会可以看的明白的。我就做个记录,翻译一下。

    /**
* The number of times this list has been <i>structurally modified</i>. 这个list的结构已经被修改过的次数
* Structural modifications are those that change the size of the 结构修改是那些改变list的size属性,
* list, or otherwise perturb it in such a fashion that iterations in 或者其他方式如迭代进度可能会产生不正确的结果
* progress may yield incorrect results.
*
* <p>This field is used by the iterator and list iterator implementation 这个字段是由迭代器和列表迭代器实现的
* returned by the {@code iterator} and {@code listIterator} methods. 代码迭代器listIterator方法返回的代码
* If the value of this field changes unexpectedly, the iterator (or list 如果此字段的值意外更改,则迭代器(list迭代器)
* iterator) will throw a {@code ConcurrentModificationException} in 将在响应迭代器的next方法,remove方法,previous(),set(),add()等方法
* response to the {@code next}, {@code remove}, {@code previous}, 抛出concurrentmodificationexception 异常
* {@code set} or {@code add} operations. This provides 这提供了
* <i>fail-fast</i> behavior, rather than non-deterministic behavior in 快速失败的行为,而不是在面对迭代过程中,并发修改的非确定性行为
* the face of concurrent modification during iteration.
*
* <p><b>Use of this field by subclasses is optional.</b> If a subclass 子类们使用这个字段是可选的,如果一个子类
* wishes to provide fail-fast iterators (and list iterators), then it 希望提供快速失败的迭代器(lsit迭代器),那么 它
* merely has to increment this field in its {@code add(int, E)} and 仅仅需要增加这个字段在他的 add,remove,方法
* {@code remove(int)} methods (and any other methods that it overrides (或者其他任何修改了list结构的方法)
* that result in structural modifications to the list). A single call to 一个单一的调用
* {@code add(int, E)} or {@code remove(int)} must add no more than add()或者remove()方法,必须增加不超过
* one to this field, or the iterators (and list iterators) will throw 1 的大小的值,给这个字段。否则,迭代器或者list迭代器将抛出
* bogus {@code ConcurrentModificationExceptions}. If an implementation ConcurrentModificationExceptions 异常 如果一个实现
* does not wish to provide fail-fast iterators, this field may be 不希望提供快速失败迭代器,这个字段可以忽视
* ignored.
*/