沙丁解牛之google guava - list

先从List说起,Guava包中只有一种List,即【abstract class】ImmutableList,其有四个实现类:EmptyImmutableList,SingletonImmutableList,RegularImmutableList,【abstract class】ImmutableAsList,如下图(红色背景属于JDK,黄色背景属于Guava):

Guava List

public abstract class com.google.common.collect.ImmutableCollection:所有Immutable集合的抽象父类,不允许null元素。
顾名思义,ImmutableCollection是不可变集合,根据《Effective Java》中的原则xx,不可变有很多优点。JDK的Collections中有一系列static unmodifiable*()方法,这些方法包装的集合也可以防止被执行修改操作,但是这种革命意志坚决不动摇是假的或者是不纯粹的,是伪装的投降主义,一个好同志要坚决抵制,例如:

title
@Test
public void testUnmodifiableList() {
final List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
System.out.println(list);// [1, 2]
final List<Integer> wrapedList = Collections.unmodifiableList(list);
System.out.println(wrapedList);// [1, 2]
list.add(3);
System.out.println(wrapedList);// [1, 2, 3]
wrapedList.add(4);// throw java.lang.UnsupportedOperationException
}

我们看java.util.Collections.unmodifiableList(List<? extends T>)的源码:

public E get(int index) {return list.get(index);}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}

该方法没做什么事情,数据结构还是原来的,只不过对原List又包装了一层而已,因此性能可能还稍微不如包装之前,因此Guava的Immutable集合诞生了,这是真正的不可变集合(实现方式也是对List接口的写操作throw new UnsupportedOperationException()),而且速度更快占用空间更小(针对空集EmptyImmutableList和单元素集合SingletonImmutableList做了优化)。

重点看RegularImmutableList,这是ImmutableList的工厂方法ImmutableList.of(…)和ImmutableList.copyOf(…)的默认产出类型。其实也没什么,只有三个transient字段:

  • int offset【偏移量,应该是预留的,构造函数未公开,暂时无用?】
  • int size【集合大小,因offset的原因size不不一定等于array的长度】
  • Object[] array【集合元素】

构造函数有三类:

ImmutableList.of()
ImmutableList.of(E)
ImmutableList.of(E, E, E)
ImmutableList.of(E, E, E, E, E...)
...
ImmutableList.copyOf(E[])
ImmutableList.copyOf(Iterator<? extends E>)
ImmutableList.copyOf(Collection<? extends E>)
...
ImmutableList.builder()
...

其他的方法都很简单,如:get(),toArray(),isEmpty(),subListUnchecked(),listIterator(),equals(),toString()等。

代码使用示例:

@Test
public void test() {
// 构造of() 适用于从几个已知元素
ImmutableList<Integer> iList = ImmutableList.of(1, 2);
System.out.println(iList);// [1, 2]
// copyOf() 适用于从一个已知集合or数组构造
iList = ImmutableList.copyOf(iList);
System.out.println(iList);// [1, 2]
iList = ImmutableList.copyOf(new Integer[] { 1, 2, 3, 4 });
System.out.println(iList);// [1, 2, 3, 4]
// 单元素集合的对象是SingletonImmutableList
iList = ImmutableList.of(6);
System.out.println(iList);// [6]
// 空集合的对象是静态变量EmptyImmutableList.INSTANCE
ImmutableList<Integer> iList1 = ImmutableList.of();
ImmutableList<Integer> iList2 = ImmutableList.of();
System.out.println(iList1 == iList2);// true
// builder()适用于元素不定的集合构造,但每一次add都是一次arrayCopy,效率不高
Builder<Integer> builder = ImmutableList.builder();
builder.add(1);
builder.add(2, 3);
builder.addAll(iList);
iList = builder.build();
System.out.println(iList);// [1, 2, 3, 6]
}

最后,总结一下。
场景:ImmutableList的使用场景,初始化一次后就只读的场景,如缓存,系统刚启动时获取的配置参数保存等。其本质就是用集合的接口使用数组。
启示:分而治之,对于空集合、单元素集合与多元素集合,分情况来处理,这样针对特殊情况的效率更高,空间更省。
命名:我之前的静态工厂方法喜欢以fromXxx()或toXxx(),instanceof()方法,以后用ofXxx(),asXxx(),construct()来命名也未尝不可。

评论