【JDK1.8】JDK1.8集合源碼閱讀——總章

1、前言

  今天開始閱讀jdk1.8的集合部分,平時在寫項目的時候,用到的最多的部分可能就是Java的集合框架,經過閱讀集合框架源碼,瞭解其內部的數據結構實現,可以深刻理解各個集合的性能特性,而且可以幫助本身在從此的開發中避免犯一些使用錯誤。另外筆者本身也是摸着石頭過河,若是有描述不當的地方,但願園友們可以不吝指出,但願可以和你們共同進步!

java

2、集合框架概覽圖

圖片集合

  能夠看到集合的基礎接口是Map, Collection以及Iterator。其他的類都實現自這3個類。segmentfault

  • 藍色爲接口,紅色爲類,綠色爲抽象類。
  • 空心三角形虛線:實現接口(implements),好像也不太準確,列如list和collection的關係是extends。由於list是接口
  • 空心三角形實線:繼承(extends)

3、基礎接口的源碼解析

3.1 Iterator接口

public interface Iterator<E> {
  boolean hasNext();
  E next();
  default void remove() {
    throw new UnsupportedOperationException("remove");
  }
  /**
  * 舉個簡單例子(把集合裏的元素每一個都輸出出來):
  * List<String> names = new ArrayList<>();
  * names.add("Joemsu");
  * names.add("GodnessY");
  * names.iterator().forEachRemaining(c -> System.out.println("hi! " + c));
  */
  default void forEachRemaining(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    while (hasNext())
      action.accept(next());
  }
}

  能夠看到Iterator接口仍是很簡單的,作到了見名知意,值得一提的是裏面的remove方法:此方法可用於在迭代中刪除結合中的元素,若是不用Iterator,在list循環中使用remove會拋異常。另外forEachRemaining()給出了簡單的例子,裏面的Consumer函數式接口有空再具體講解。

數組

3.2 Collection接口

public interface Collection<E> extends Iterable<E> {
  //值得一提的是:若是size超過Integer.MAX_VALUE也只會返回Integer.MAX_VALUE
  int size();
  boolean isEmpty();
  //若是向集合裏添加null,使用contains(null),也能夠返回true
  boolean contains(Object o);
  Iterator<E> iterator();
  /**
   * 深層拷貝,修改數組的數據不會對集合裏的元素產生影響。
   * 注意:只能返回Object[],不能強制轉換其餘類型,如須要轉型,使用下面帶泛型的方法。
   */
  Object[] toArray();
  <T> T[] toArray(T[] a);
  boolean add(E e);
  boolean remove(Object o);
  boolean containsAll(Collection<?> c);
  boolean addAll(Collection<? extends E> c);
  boolean removeAll(Collection<?> c);
  //保留c集合裏的元素
  boolean retainAll(Collection<?> c);
  void clear();
  boolean equals(Object o);
  //如過a.equals(b),則hashCode()確定相同,反之不必定
  int hashCode();
  
  //針對parallelStream()添加的方法,用於分割集合,進行並行處理
  @Override
  default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, 0);
  }
  
  /**
  * 若是知足filter,則刪除,舉個栗子:
  * Collection<String> myHeart = new ArrayList<>();
  * myHeart.add("Boduolaoshi");
  * myHeart.add("GodnessY");
  * System.out.println("before: " + myHeart.size());
  * myHeart.removeIf(s -> s.equals("Boduolaoshi"));
  * System.out.println("after: " + myHeart.size());
  */
  default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
      if (filter.test(each.next())) {
        each.remove();
        removed = true;
      }
    }
    return removed;
  }
  
  default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
  }
  
  //採用並行處理,使用多核cpu的特性
  default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
  }
}

  須要注意的一些地方已經在註釋這裏特別說明過了,另外對於spliterator(),不是特別清楚的園友們,能夠點擊查看這裏,回答的已經很詳細了。

數據結構

3.3 Map接口

public interface Map<K,V> {
  //一樣的,若是size超過Integer.MAX_VALUE也只會返回Integer.MAX_VALUE
  int size();
  boolean isEmpty();
  boolean containsKey(Object key);
  boolean containsValue(Object value);
  V get(Object key);
  V put(K key, V value);
  V remove(Object key);
  void putAll(Map<? extends K, ? extends V> m);
  void clear();
  //對set的變更會影響到map,反過來也同樣
  Set<K> keySet();
  //對Collection的變更會影響到map,反過來也同樣
  Collection<V> values();
  //對Set的變更會影響到map,反過來也同樣
  Set<Map.Entry<K, V>> entrySet();
  boolean equals(Object o);
  int hashCode();
  
  //Entry start
  interface Entry<K,V> {
    K getKey();
    V getValue();
    V setValue(V value);
    boolean equals(Object o);
    int hashCode();
    //使用默認方法對Key進行比較
    public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey(){
      return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> c1.getKey().compareTo(c2.getKey());
    }
    //使用默認方法對Value比較
    public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
      return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> c1.getValue().compareTo(c2.getValue());
    }
    /**
    * 本身傳比較的方法,舉個栗子:
    * Map<String, Integer> map = new HashMap<>();
    * map.put("sorted", 2);
    * map.put("collect", 1);
    * map.put("each", 3);
    * System.out.println("before sort");
    * map.entrySet().forEach(System.out::println);
    * System.out.println("after sort");
    * map.entrySet()
    *     .stream()
    *     .sorted(Map.Entry.comparingByKey((a, b) -> a.length() - b.length()))
    *     .collect(Collectors.toList()).forEach(System.out::println);
    */
    public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
      Objects.requireNonNull(cmp);
      return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
    }
    public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
      Objects.requireNonNull(cmp);
      return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
    }
  }
  //Entry end
  
  //獲取指定key 的value,沒有則返回默認值
  default V getOrDefault(Object key, V defaultValue) {
    V v;
    return (((v = get(key)) != null) || containsKey(key))
      ? v
      : defaultValue;
  }
  
  /**
  * 對每隊鍵值對操做: map.forEach((i, j) -> System.out.println(i + j))
  * 注意這裏的(i, j)的類型與你初始化map的鍵值類型對應,i即K, j即V 
  */
  default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
      K k;
      V v;
      try {
        k = entry.getKey();
        v = entry.getValue();
      } catch(IllegalStateException ise) {
        // this usually means the entry is no longer in the map.
        throw new ConcurrentModificationException(ise);
      }
      action.accept(k, v);
    }
  }
  
  /**
  * 傳入BiFunction類型,對每一個鍵值對進行處理,返回類型與V類型相同
  * Map<String, Integer> map = new HashMap<>();
  * map.put("hi", 3);
  * map.put("hello", 4);
  * BiFunction<String, Integer, Integer> bi = (a, b) -> a.length() + b; //爲了容易理解,這麼寫
  * map.forEach((i, j) -> System.out.println(i + ":" + j));
  * map.replaceAll(bi);
  * map.forEach((i, j) -> System.out.println(i + ":" + j));
  */
  default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
    Objects.requireNonNull(function);
    for (Map.Entry<K, V> entry : entrySet()) {
      K k;
      V v;
      try {
        k = entry.getKey();
        v = entry.getValue();
      } catch(IllegalStateException ise) {
        // this usually means the entry is no longer in the map.
        throw new ConcurrentModificationException(ise);
      }

      // ise thrown from function is not a cme.
      v = function.apply(k, v);

      try {
        entry.setValue(v);
      } catch(IllegalStateException ise) {
        // this usually means the entry is no longer in the map.
        throw new ConcurrentModificationException(ise);
      }
    }
  }
  
  //若是爲空的話,插入
  default V putIfAbsent(K key, V value) {
    V v = get(key);
    if (v == null) {
      v = put(key, value);
    }

    return v;
  }
  
  default boolean remove(Object key, Object value) {
    Object curValue = get(key);
    if (!Objects.equals(curValue, value) ||
        (curValue == null && !containsKey(key))) {
      return false;
    }
    remove(key);
    return true;
  }
  
  default boolean replace(K key, V oldValue, V newValue) {
    Object curValue = get(key);
    if (!Objects.equals(curValue, oldValue) ||
        (curValue == null && !containsKey(key))) {
      return false;
    }
    put(key, newValue);
    return true;
  }
  
  default V replace(K key, V value) {
    V curValue;
    if (((curValue = get(key)) != null) || containsKey(key)) {
      curValue = put(key, value);
    }
    return curValue;
  }
  
  //若是key不存在,則經過mappingFunction生成value,並插入
  default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
      V newValue;
      if ((newValue = mappingFunction.apply(key)) != null) {
        put(key, newValue);
        return newValue;
      }
    }

    return v;
  }
  
  //若是存在key對應的值,則經過remappingFunction來計算新的value,(value不爲空)而後更新,爲空則刪除key
  default V computeIfPresent(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    Objects.requireNonNull(remappingFunction);
    V oldValue;
    if ((oldValue = get(key)) != null) {
      V newValue = remappingFunction.apply(key, oldValue);
      if (newValue != null) {
        put(key, newValue);
        return newValue;
      } else {
        remove(key);
        return null;
      }
    } else {
      return null;
    }
  }
  
  default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
    V oldValue = get(key);

    V newValue = remappingFunction.apply(key, oldValue);
    if (newValue == null) {
      // delete mapping
      if (oldValue != null || containsKey(key)) {
        // something to remove
        remove(key);
        return null;
      } else {
        // nothing to do. Leave things as they were.
        return null;
      }
    } else {
      // add or replace old mapping
      put(key, newValue);
      return newValue;
    }
  }
  
  //將舊的oldValue和新的傳進去value經過remappingFunction進行處理,而後更新
  default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    Objects.requireNonNull(remappingFunction);
    Objects.requireNonNull(value);
    V oldValue = get(key);
    V newValue = (oldValue == null) ? value :
    remappingFunction.apply(oldValue, value);
    if(newValue == null) {
      remove(key);
    } else {
      put(key, newValue);
    }
    return newValue;
  }
}

  那麼Map的接口源碼閱讀就到這裏。

app

4、總結

  總的來講,jdk1.8集合與以前版本不一樣的地方就是加入了不少default方法,以及使用了各類函數型接口,但整體來講仍是比較好理解的。後面會更新其餘的實現類,謝謝各位園友觀看,若是有描述不對的地方歡迎指正。框架

相關文章
相關標籤/搜索