基础
Immutable是guava提供的一系列不可变类
1.不可变代表着线程安全,线程调用时完全不用考虑线程安全的问题(不过个人认为意义不大,因为这个不可变是在封锁修改方法的前提下保证的,非不可变类不对其进行修改也完全可以实现同样的效果)
2Guava不可变集合不仅仅是源数据结构的视图,而是它的副本,使得对原始结构的更改不会影响复制的不可变集合。
3.转成不可变类再输出是一个防御式编程的手段.
ImmutableList
com.google.common.collect.ImmutableList 不可变的List结构
极其完善的健壮性
四个copyof方法 覆盖了所有的入参情况
public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements)
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements)
public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements)
public static <E> ImmutableList<E> copyOf(E[] elements)
并且第一个方法解析后的值可以直接利用下一个方法
public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {
// TODO(kevinb): is this here only for GWT?
checkNotNull(elements);
return (elements instanceof Collection)
? copyOf((Collection<? extends E>) elements)
: copyOf(elements.iterator());
}
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
if (elements instanceof ImmutableCollection) {
@SuppressWarnings("unchecked") // all supported methods are covariant
ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
return list.isPartialView() ? ImmutableList.<E>asImmutableList(list.toArray()) : list;
}
return construct(elements.toArray());
}
public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) {
// We special-case for 0 or 1 elements, but going further is madness.
if (!elements.hasNext()) {
return of();
}
E first = elements.next();
if (!elements.hasNext()) {
return of(first);
} else {
//这里有一条岔路之后再说
return new ImmutableList.Builder<E>().add(first).addAll(elements).build();
}
}
public static <E> ImmutableList<E> copyOf(E[] elements) {
switch (elements.length) {
case 0:
//同样是对于常用情况 的特殊处理
return of();
case 1:
return of(elements[0]);
default:
return construct(elements.clone());
}
}
对不同类型的数据进行处理 之后调用construct()方法
private static <E> ImmutableList<E> construct(Object... elements) {
return asImmutableList(checkElementsNotNull(elements));
}
//入参校验后
static <E> ImmutableList<E> asImmutableList(Object[] elements) {
return asImmutableList(elements, elements.length);
}
static <E> ImmutableList<E> asImmutableList(Object[] elements, int length) {
switch (length) {
case 0:
return of();
case 1:
return of((E) elements[0]);
default:
if (length < elements.length) {
elements = Arrays.copyOf(elements, length);
}
return new RegularImmutableList<E>(elements);
}
}
最后交由两种方法实现
1.构建RegularImmutableList对象 又体现了懒加载的思想
@VisibleForTesting final transient Object[] array;
RegularImmutableList(Object[] array) {
this.array = array;
}
@Override
public int size() {
return array.length;
}
@Override
boolean isPartialView() {
return false;
}
//除了这个方法以外没有进行数据的处理
//这里进行数据处理也是使用native方法
@Override
int copyIntoArray(Object[] dst, int dstOff) {
System.arraycopy(array, 0, dst, dstOff, array.length);
return dstOff + array.length;
}
// The fake cast to E is safe because the creation methods only allow E's
@Override
@SuppressWarnings("unchecked")
public E get(int index) {
return (E) array[index];
}
2.交由JDK的Arrays.copyOf()方法执行
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
可以看到最后也是使用System.arraycopy()进行拷贝.
WIKI 这个为什么不也用第一种方法来实现呢?
还有一条岔路
return new ImmutableList.Builder<E>().add(first).addAll(elements).build();
对于复杂情况 使用建造者模式进行处理
public ImmutableList<E> build() {
forceCopy = true;
//可以看到 最后还是调用了同样的方式
return asImmutableList(contents, size);
}
效率&代码量
public static <E> ImmutableList<E> of() {
return (ImmutableList<E>) EMPTY;
}
public static <E> ImmutableList<E> of(E element) {
return new SingletonImmutableList<E>(element);
}
public static <E> ImmutableList<E> of(E e1, E e2) {
return construct(e1, e2);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3) {
return construct(e1, e2, e3);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4) {
return construct(e1, e2, e3, e4);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5) {
return construct(e1, e2, e3, e4, e5);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
return construct(e1, e2, e3, e4, e5, e6);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
return construct(e1, e2, e3, e4, e5, e6, e7);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
return construct(e1, e2, e3, e4, e5, e6, e7, e8);
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9);
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) {
return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11);
}
这个你敢信是谷歌工程师写出来的代码吗?
从1个参数到11个参数全部写了实现类,超过12个参数才有了通用方法
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, E e12, E... others) {
checkArgument(
others.length <= Integer.MAX_VALUE - 12,
"the total number of elements must fit in an int");
Object[] array = new Object[12 + others.length];
array[0] = e1;
array[1] = e2;
array[2] = e3;
array[3] = e4;
array[4] = e5;
array[5] = e6;
array[6] = e7;
array[7] = e8;
array[8] = e9;
array[9] = e10;
array[10] = e11;
array[11] = e12;
System.arraycopy(others, 0, array, 12, others.length);
return construct(array);
}
用来大量的代码量来尽量提升运行速度 这是谷歌工程师的选择
ImmutableMap
不可变HashMap
组合数据结构
在构建数据结构的过程中有一个方法:
static <K, V> ImmutableMap<K, V> fromEntryArray(int n, Entry<K, V>[] entryArray) {
checkPositionIndex(n, entryArray.length);
if (n == 0) {
return (RegularImmutableMap<K, V>) EMPTY;
}
Entry<K, V>[] entries;
if (n == entryArray.length) {
entries = entryArray;
} else {
entries = createEntryArray(n); //空的
}
int tableSize = Hashing.closedTableSize(n, MAX_LOAD_FACTOR);
ImmutableMapEntry<K, V>[] table = createEntryArray(tableSize);
int mask = tableSize - 1;
for (int entryIndex = 0; entryIndex < n; entryIndex++) {
Entry<K, V> entry = entryArray[entryIndex]; //取数据
K key = entry.getKey();
V value = entry.getValue();
checkEntryNotNull(key, value);
int tableIndex = Hashing.smear(key.hashCode()) & mask;
@Nullable ImmutableMapEntry<K, V> existing = table[tableIndex];
// prepend, not append, so the entries can be immutable
ImmutableMapEntry<K, V> newEntry =
(existing == null)
? makeImmutable(entry, key, value)
: new NonTerminalImmutableMapEntry<K, V>(key, value, existing);
table[tableIndex] = newEntry; //新建的,符合hashMap结构
entries[entryIndex] = newEntry; //按顺序存放的数组
int bucketSize = checkNoConflictInKeyBucket(key, newEntry, existing);
if (bucketSize > MAX_HASH_BUCKET_LENGTH) {
// probable hash flooding attack, fall back to j.u.HM based implementation and use its
// implementation of hash flooding protection
return JdkBackedImmutableMap.create(n, entryArray);
}
}
return new RegularImmutableMap<>(entries, table, mask);
}
这段代码中构建了两个数据相同的对象(数据结构不同)
table[tableIndex] = newEntry; //新建的,符合hashMap结构
entries[entryIndex] = newEntry; //按顺序存放的数组
在看这段代码的过程中 感觉我需要的是HashMap的数据结构为什么要建立一个数组数据结构的对象呢? 这不是对内存的极大的浪费吗
//遍历
public void forEach(BiConsumer<? super K, ? super V> action) {
checkNotNull(action);
for (Entry<K, V> entry : entries) {
action.accept(entry.getKey(), entry.getValue());
}
}
//size
public int size() {
return entries.length;
}
//get
K get(int index) {
return map.entries[index].getKey();
}
WIKI 在这几个方法中都使用了数据结构为数组的对象 , 并且效率非常高 , 之前只见过HashMap这种链式组合的数据结构 , 没想到可以为了一些方法的效率在一个实现类中定义两种数据结构 , 以提升性能