Guava源碼閱讀分析 - Lists

一、guava中Lists使用場景

reverse()方法的使用場景如下,返回[3, 2, 1] (一個list)

Lists.reverse(Arrays.asList(1, 2, 3))

partition方法的使用場景如下,返回[[1, 2, 3], [4, 5]] (一個list)

Lists.partition(Arrays.asList(1, 2, 3,4,5),3)

transform()方法使用場景如下,結果爲[4, 2, 3] (一個list)

List<String> list = Lists.newArrayList("我在閱讀","源碼","很開心");
System.out.println(Lists.transform(list, e->e.length()));//返回list中每個元素的長度的list

二、源碼分析(guava中好喜歡用靜態內部類啊啊)

①Reverse方法,真的要把一個list reverse一下嗎?

reverse方法方法並不是真的把list reverse一下,返回的reverseList的底層原理是原List支持,只是取了反轉後的位置元素而已,所以,對原先的List的改變會導致reverseList也跟着改變,其中傳進來的List有四種類型情況:

public static <T> List<T> reverse(List<T> list) {
  if (list instanceof ImmutableList) {
    //如果是ImmutableList類型,則調用該類型list的reverse()方法獲得reversed的list
    return ((ImmutableList<T>) list).reverse();
  } else if (list instanceof ReverseList) {
     //如果是ReverseList<T>類型,之間返回它的內部成員變量forwardList
     return ((ReverseList<T>) list).getForwardList();
  } else if (list instanceof RandomAccess) {
    //如果指定的list是RandomAccess類型的,返回的list也是random-access的,其中              RandomAccessReverseList<T>也是Lists中的靜態內部類,繼承自ReverseList<T>類
    return new RandomAccessReverseList<>(list);
  } else {
    //返回ReverseList<>類型,list的參數會被賦值給ReverseList的成員變量private final List<T> forwardList;
    return new ReverseList<>(list);
  }
}

ReverseList是Lists的靜態內部類,它繼承自AbstractList抽象List接口,在ReverseList中有個與自己逆向的forwardList類型

private static class ReverseList<T> extends AbstractList<T> {
  private final List<T> forwardList;
  ...
  //由原先的index計算出逆轉後對應的index, 如0123,第一個位置index爲0,逆轉後爲(size-1)-index=(4-1)-0=3,所以逆轉list對應index爲3
   private int reverseIndex(int index) {
      int size = size();
      checkElementIndex(index, size);
      return (size - 1) - index;
    }
  //reversePosition和上面原理類似,主要用於出入刪除元素位置
    private int reversePosition(int index) {
      int size = size();
      checkPositionIndex(index, size);
      return size - index;
    }
  //後面是一些AbstractList中方法的實現,包括迭代器等
  ...
}
②partition方法

partition方法返回連續的subList即子list,每一個子list長度 一樣,內部通過list.subList(start, end)實現但最後一個list可能長度不夠小一點,輸出的List是不可改變的,但是原list的最新狀態映射。其中Partition<>是一個繼承自AbstractList<List>的靜態內部類(又是靜態內部類!!!),RandomAccessPartition在Partition基礎上多實現了RandomAccess接口而已

public static <T> List<List<T>> partition(List<T> list, int size) {
  checkNotNull(list);
  checkArgument(size > 0);
  return (list instanceof RandomAccess)
      ? new RandomAccessPartition<>(list, size)
      : new Partition<>(list, size);
}
private static class Partition<T> extends AbstractList<List<T>> {
  final List<T> list;//需要切分的list
  final int size;//每個字list的大小

  Partition(List<T> list, int size) {
    this.list = list;
    this.size = size;
  }
  
  @Override
  public List<T> get(int index) {
    checkElementIndex(index, size());//檢查邊界
    int start = index * size;//去第n個list,則開始下標爲n*size
    int end = Math.min(start + size, list.size());//所取list的end下標
    return list.subList(start, end);//通過sublist方法取list的子list
  }

  @Override
  public int size() {
    //真個list分爲幾個子list,向上取整
    return IntMath.divide(list.size(), size, RoundingMode.CEILING);
  }
   ...
}
③transform,將集合裏每個對象轉換完然後再填入一個新的list嗎?

TransformingSequentialList<F, T>是一個繼承自AbstractSequentialList並實現了序列化接口的靜態內部類,它有兩個成員常量,一個是待轉化的原始list,一個是Function<? super F, ? extends T> function函數式接口,作用是通過迭代,運用function中的apply函數把list中的每個元素轉爲需要轉化成的元素,因此只是改了迭代方法,並沒有轉化後填入一個新的list。需要重寫函數式接口Function中的apply方法,在此學習借鑑了Function接口的用法精髓

public static <F, T> List<T> transform(
    List<F> fromList, Function<? super F, ? extends T> function) {
  return (fromList instanceof RandomAccess)
      ? new TransformingRandomAccessList<>(fromList, function)
      : new TransformingSequentialList<>(fromList, function);
}
private static class TransformingSequentialList<F, T> extends AbstractSequentialList<T>
    implements Serializable {
  final List<F> fromList;//待轉化的List
  final Function<? super F, ? extends T> function;//函數式接口Function

  TransformingSequentialList(List<F> fromList, Function<? super F, ? extends T> function) {
    this.fromList = checkNotNull(fromList);//檢查null
    this.function = checkNotNull(function);//檢查null
  }

  /**
   * The default implementation inherited is based on iteration and removal of each element which
   * can be overkill. That's why we forward this call directly to the backing list.
   */
  @Override
  public void clear() {
    fromList.clear();
  }

  @Override
  public int size() {
    return fromList.size();//轉化後的list的size和原理的List一樣
  }

  @Override
  public ListIterator<T> listIterator(final int index) {
    //在迭代方法中通過apply方法轉化元素
    return new TransformedListIterator<F, T>(fromList.listIterator(index)) {
      @Override
      T transform(F from) {
        return function.apply(from);
      }
    };
  }

  @Override
  public boolean removeIf(Predicate<? super T> filter) {
    checkNotNull(filter);
    //評估條件是否成立,成立則刪掉該元素,函數式接口Predicate的運用
    return fromList.removeIf(element -> filter.test(function.apply(element)));
  }

  private static final long serialVersionUID = 0;
}
拓展:有時間再研究下各種迭代器的源碼原理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章