Guava源码阅读计划:collect.Immutable

基础

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这种链式组合的数据结构 , 没想到可以为了一些方法的效率在一个实现类中定义两种数据结构 , 以提升性能

猜你喜欢

转载自blog.csdn.net/qq_30054997/article/details/81304927