天天看點

Java 集合系列(8): Map接口源碼

package java.util;

import java.io.Serializable;  
import java.lang.*;  
import java.util.*;  
import java.util.function.*;  
import java.util.function.BiFunction;  
  
/** 
 * 
 * Map是一個有鍵值對映射的對象.map不能包含相同的key,每一個key至多能映射一個value. 
 * 
 * 這個接口替代了Dictionary這個類,Dictionary是抽象類而非接口. 
 * (替代原因:接口總是優于抽象類,原因可檢視<<effective java>>第18條) 
 * 
 * Map接口提供了3個集合視圖,包括:keys的set集合; values的集合; key-value的set集合.(注意:values集合不是set類型,因為value可相同) 
 * Map傳回元素的順序,取決于:map對應的某個集合視圖疊代器的順序. 
 * 一些map的實作,比如TreeMap類,對于map傳回元素的順序有特殊的規定; 
 * 其它的map實作類,比如HashMap類,就沒有特殊的規定. 
 * 
 * 注意:如果把易變的對象作為map的key,那麼一定要引起你的特别關注. 
 * 如果map中的一個key發生了改變,并且影響了equals()方法的使用,那麼map并不會提示我們. 
 * 是以,我們禁止使用map自身作為map的key. 
 * 盡管我們允許使用map自身作為value值,但是我們還是要注意:equals()方法和hashCode()方法在這樣定義的map裡面可能不能正常使用. 
 * 
 * 所有的通用map實作類都應該提供兩個"标準"的構造器函數: 
 * 一個是無參且傳回類型為void的函數; 
 * 另一個就是僅含有一個參數且類型為map類型的的構造方法,這個方法會使用其參數構造一個新的map,且新的map和參數map有相同的key和value. 
 * 結果就是,第二個構造函數允許使用者複制任何map,新生成一個和給定map一樣的map. 
 * 但是,map接口這裡沒辦法強制執行這一建議(因為接口裡面不能包含構造器函數),不過JDK裡面所有通用的map實作類都是符合這一點要求的. 
 * 
 * 如果一個操作不被map支援,且這個操作會更改map的結構,這樣的操作已經在map接口中做了具體的定義,并且會傳回 
 * UnsupportedOperationException異常. 
 * 如果是上述這種情況,這些方法可能會抛出UnsupportedOperationException異常,但并不是說一定會抛出這個異常.而且調用也不會對map産生什麼 
 * 影響.比如,在一個不可更改的map上面調用不被允許的putAll方法,則會抛出異常. 
 * 
 * 一些map的實作類在key和value的取值上面會有一些規定.比如,一些map實作類不允許key或者value為null; 
 * 而一些是在key的類型上面做了限制.嘗試插入一些不符合規定的key或者value,會抛出非檢查型異常, 
 * 類似NullPointerException異常,ClassCastException異常. 
 * 嘗試查詢不符合規定的key或者value也會抛出異常,或者僅傳回false;具體是上述哪種情況,和具體的map實作類自身相關. 
 * 更一般的情況是,對于非法的key或者value進行的操作,插入失敗可能會抛出異常,但是也可能插入成功,這取決于具體的map實作類. 
 * 這類型的異常被認為是map接口的可選擇的. 
 * 
 * map接口是java集合架構中的一個成員. 
 * 
 * 集合架構接口定義了很多種和equals()方法相關的實作. 
 * 比如,containsKey()方法:目前僅當map包含了鍵k的定義是:key==null ? k==null : key.equals(k) 
 * 這一規範的寫法,不能被了解為為:如果調用方法使用的是一個非null參數的話,然後隻是再調用key.equals(k)方法就可以了. 
 * 具體實作可以通過避免調用equals()方法來實作優化,比如,可以先比較兩個key的哈希值. 
 * (哈希值保證了,如果兩個對象的哈希值都不相同,那麼這兩個對象肯定不會相同).更一般的情況是,大量集合架構接口的實作類可以充分利用 
 * 底層對象(Object)的方法的優勢,隻要實作者認為他們這麼做是合理的. 
 * 
 * 
 * 注意啦:這裡的containsKey()方法還是和自己想象的不一樣的,我真的以為如果key不是null,那就是直接調用equals()方法啦呢.這一點可以通過 
 * containsKey()方法調用的getEntry方法源碼看出,在if的判定條件中,equals是作為最後一個判定條件出現的,也就是說如果if前面的判定 
 * 條件為true,那麼是不會調用equals()方法的. 
 * 
 * @author  Josh Bloch 
 * @see java.util.HashMap 
 * @see TreeMap 
 * @see Hashtable 
 * @see SortedMap 
 * @see Collection 
 * @see Set 
 * @since 1.2 
 */  
public interface Map<K,V> {  
    //以下為map的查詢操作  
  
    /** 
     * 傳回map中key-value映射的個數.如果map包含的key-value個數超過了Integer.MAX_VALUE這個數, 
     * 則傳回Integer.MAX_VALUE. 
     */  
    int size();  
  
    /** 
     * 如果map沒有存儲任何key-value,則傳回true. 
     */  
    boolean isEmpty();  
  
    /** 
     * 如果map存儲了指定的key,則傳回true.更一般的情況是,當且僅當map包含了一個key的映射: 
     * 映射情況是:key==null ? k==null : key.equals(k),此時傳回true. 
     */  
    boolean containsKey(Object key);  
  
    /** 
     * 如果map中至少有一個key能映射到指定的value,那麼就傳回true.更一般的情況是,當且僅當value==null ? v==null : value.equals(v) 
     * 條件成立,才傳回true. 
     * 在所有map接口的實作類中,這一操作都需要map大小的線性時間來完成. 
     */  
    boolean containsValue(Object value);  
  
    /** 
     * 傳回指定key映射的value.如果map沒有指定的key,則傳回null. 
     * 
     * 更一般的情況是:如果map包含了一個滿足條件key==null ? k==null :key.equals(k))的映射, 
     * 那麼方法就會傳回對應的value;否則,傳回null.(當然這樣的映射最多有一個) 
     * 
     * 如果map允許null值,傳回null值并不一定意味着map不存在指定key的映射;因為這也可能是這個key對應的value值就是null. 
     * 是以,get方法也可能被用于區分這兩種情況. 
     */  
    V get(Object key);  
  
    // Modification Operations ,以下為修改map的操作  
  
    /** 
     * put方法是将指定的key-value存儲到map裡面的操作.如果map之前包含了一個此key對應的映射,那麼此key對應的舊value值會被 
     * 新的value值替換. 
     */  
    V put(K key, V value);  
  
    /** 
     * remove方法用于移除map中已有的某個key.更一般的講,如果map包含了一個滿足條件key==null ?  k==null : key.equals(k) 
     * 的映射,這一映射就會被移除.(map最多包含一個這樣的映射) 
     * 
     * 本方法會傳回移除的key對應的value值,如果map這個key沒有對應的value值,則傳回null. 
     * 
     * 如果map允許null值,那麼傳回null值并不一定表明map不包含對應key的映射值;因為這也可能是key本身對應的value值就是null. 
     * 
     * 一旦此方法被調用,那麼map就不會再包含這個key的映射了. 
     */  
    V remove(Object key);  
  
  
    //塊操作  
  
    /** 
     * putAll方法是将一個指定map的映射拷貝到目前map.這一操作類似于将指定map的key-value對通過put方法一個個拷貝過來. 
     * 在拷貝過程中,如果指定的這個map被更改了,那麼這時候會出現什麼情況,并不清楚. 
     */  
    void putAll(Map<? extends K, ? extends V> m);  
  
    /** 
     * 移除map中所有的映射. 
     * 調用此方法後,map會變為空. 
     */  
    void clear();  
  
  
    // Views ,視圖  
  
    /** 
     * 此方法:傳回map包含所有的key的一個set集合視圖. 
     * 這個set集合由map作為背景支援,是以map的改變會反映在set集合裡面,同樣的 
     * set集合的更改也會反映在map裡面.(這和ArrayList中的subList方法一樣,任意一方的更改都會在另一方展現出來) 
     * 如果在疊代過程中,map被修改了結構(出去通過疊代器的remove方法對map結構的改變),疊代器的輸出結果會受到什麼影響, 
     * 這一點并沒有給出規定. 
     * 此方法傳回的set集合支援移除元素,同時會從map中删除對應的映射.可以删除元素的操作方法有5個: 
     * <tt>Iterator.remove</tt>, 
     * <tt>Set.remove</tt>, 
     * <tt>removeAll</tt>, 
     * <tt>retainAll</tt>, 
     * <tt>clear</tt> 
     * 此方法傳回的set集合不支援add或者addAll操作. 
     * 也就是隻有删除操作,沒有添加操作.畢竟add類型的操作是沒有意義的.因為此set集合傳回的是map的keys的集合.你添加了key, 
     * 但是沒有辦法同時添加對應的value,隻會給後面的操作帶來性能影響,沒有其它什麼意義. 
     * 如果你執行了add類型操作會抛出UnsupportedOperationException異常.(這裡可以自己運作一下代碼) 
     */  
    Set<K> keySet();  
  
    /** 
     * values方法傳回map記憶體儲的所有值的集合(畢竟值集合中,值可以有重複的,是以此方法和上面的傳回的key集合的結果類型不一樣,因為key肯定 
     * 都是不同的). 
     * 這一集合也由map集合提供背景支援.是以map的更改會展現在傳回的集合裡面,反之亦然.(這一點和keySet方法完全一樣) 
     * 基于這個集合疊代器,對map進行周遊.在周遊過程中,如果map結構發生了改變(改變不包括:疊代器自身執行的remove方法),疊代器的輸出結果是否 
     * 受到影響,這一點并沒有定義. 
     * 這一傳回集合支援移除元素,這會同時移除map中對應的映射.移除操作類型包括5類: 
     * <tt>Iterator.remove</tt>, 
     * <tt>Collection.remove</tt>, 
     * <tt>removeAll</tt>, 
     * <tt>retainAll</tt>, 
     * <tt>clear</tt> 
     * 
     * 注意:傳回集合不支援add或者addAll操作.如果你執行add類型操作會抛出UnsupportedOperationException異常.(這裡可以自己測試一下, 
     * 能加深了解.) 
     * 
     * 
     * @return a collection view of the values contained in this map 
     */  
    Collection<V> values();  
  
    /** 
     * 此方法傳回map裡存儲的所有映射的視圖. 
     * 當然,這個傳回的set集合,也由map作為背景支援(這一點和前兩種方法一樣),是以對map的改變會展現在set上面,反之亦然. 
     * 基于set集合的疊代器在周遊過程中,如果map結構發生了改變(除去疊代器自身的remove方法造成的map結構改變,或者疊代器對map條目調用了setValue 
     * 方法),則疊代器對輸出結果的影響是怎麼樣的,并沒有給出定義. 
     * 傳回的set集合支援移除元素,這種移除操作會同時反映在map上面. 
     * 移除操作類型包括5種: 
     * <tt>Iterator.remove</tt>, 
     * <tt>Set.remove</tt>, 
     * <tt>removeAll</tt>, 
     * <tt>retainAll</tt>, 
     * <tt>clear</tt> 
     */  
    Set<Map.Entry<K, V>> entrySet();  
  
    /** 
     * map條目(key-value對). 
     * Map.entrySet方法傳回的就是map的集合視圖,map視圖中的元素就是來源于此類. 
     * 擷取map條目的唯一方式就是來源于集合視圖的疊代器.隻有在疊代的過程中,Map.Entry對象才是有效的; 
     * 通常,如果通過疊代器獲得的map條目,在周遊過程中,作為背景支援的map被修改了,那麼map條目會如何被影響,對此 
     * 并沒有做出具體規定(當然此處說的map修改不包括setValue方法的調用). 
     */  
    interface Entry<K,V> {  
        /** 
         * 擷取目前map條目對應的key 
         */  
        K getKey();  
  
        /** 
         * 傳回map條目對應的value值. 
         * 如果映射從背景map中移除了(通過疊代器的remove方法),這一調用的結果會出現什麼影響未被定義. 
         */  
        V getValue();  
  
        /** 
         * 用指定值替換目前條目中的value.(這一更改會被寫入map中,自己調試一下代碼就能知道了). 
         * 如果映射從map中被移除了,再調用這一方法,會産生什麼異常并沒有定義. 
         */  
        V setValue(V value);  
  
        /** 
         * 将指定對象和目前條目做比較. 
         * 如果給定的對象是一個條目并且兩個條目代表同一個映射,則傳回true. 
         * 一般,兩個條目擁有相同映射滿足的條件是: 
         * if( 
         *     (e1.getKey()==null ? 
         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  && 
         *     (e1.getValue()==null ? 
         *      e2.getValue()==null : e1.getValue().equals(e2.getValue())) 
         * ) 
         * 上面的兩個條件保證了,對Map.Entry接口的不同實作,equals方法都能正确. 
         */  
        boolean equals(Object o);  
  
        /** 
         * 傳回map條目的哈希值. 
         * map條目的哈希值定義是:二者求異或值 
         * (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^ 
         *     (e.getValue()==null ? 0 : e.getValue().hashCode()) 
         * 這才能保證兩個條目相等時,通過Object.hashCode方法得到的他們的哈希值也一定是相等的. 
         */  
        int hashCode();  
    }  
  
    // 比較和hash操作  
    /** 
     * 用于對比兩個map是否相等. 
     * 如果給定的對象是一個map且兩個map的映射一緻,則傳回true. 
     * 一般,兩個map的映射一緻,要滿足的條件是: 
     * m1.entrySet().equals(m2.entrySet()) 
     * 這就保證了實作了map接口的不同類對于equals方法的使用才是正确的. 
     */  
    boolean equals(Object o);  
  
    /** 
     * 傳回map的哈希值. 
     * map的哈希值被定義為:這個map的entrySet視圖的每一個條目的哈希值的總和. 
     * 這就保證了任意兩個map相等,則他們的哈希值一定相等,這也是Object類對哈希值的普遍要求(哈希值作為兩個對象相等的 
     * 必要非充分條件). 
     * @see Map.Entry#hashCode() 
     * @see Object#equals(Object) 
     * @see #equals(Object) 
     */  
    int hashCode();  
  
  
    /*----------以下均為jdk8新增内容-----------*/  
    /** 
     * 傳回一個比較map.entry的比較器,按照key的自然順序排序. 
     * 傳回的比較器支援序列化. 
     * 如果map中的entry有key=null情況,則抛出空指針異常(因為傳回結果要按照key排序) 
     * 注意:傳入參數k必須支援Comparable接口,因為需要按照key排序. 
     * @see java.lang.Comparable 
     * @since 1.8 
     */  
    public static <K extends java.lang.Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {  
        return (Comparator<Map.Entry<K, V>> & Serializable)  
                (c1, c2) -> c1.getKey().compareTo(c2.getKey());  
    }  
  
    /** 
     * 傳回一個map.entry的比較器,按照value的自然順序排序. 
     * 傳回的比較器支援序列化. 
     * 如果map中的entry有value=null情況,則抛出空指針異常(因為傳回結果要按照value排序) 
     * 注意:傳入參數value必須支援Comparable接口,因為按照value排序. 
     * @see java.lang.Comparable 
     * @since 1.8 
     */  
    public static <K, V extends java.lang.Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {  
        return (Comparator<Map.Entry<K, V>> & Serializable)  
                (c1, c2) -> c1.getValue().compareTo(c2.getValue());  
    }  
  
    /** 
     * 傳回一個map.entry的比較器,根據傳入比較器對key排序. 
     * 如果傳入的比較器支援序列化,則傳回的結果比較器也支援序列化. 
     * @since 1.8 
     */  
    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());  
    }  
  
    /** 
     * 傳回一個map.entry的比較器,根據傳入比較器對value排序. 
     * 如果傳入的比較器支援序列化,則傳回的結果比較器也支援序列化. 
     * @since 1.8 
     */  
    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());  
    }  
}  
  
    /*----以下為:比較方法  and  hash方法-----*/  
    /** 
     * 将傳入對象和目前map進行比較. 
     * 傳回結果為true需要滿足兩個條件: 
     * 1.傳入對象類型為map類型 
     * 2.傳入對象和目前map鍵值對完全一緻. 
     * 更标準的講,兩個map的entrySet在equals結果為true,則表示鍵值對一緻.這才能保證對于實作map接口的不同類在 
     * equals方法調用過程中正常使用. 
     */  
    boolean equals(Object o);  
  
    /** 
     * 傳回map的哈希值. 
     * map的哈希值=sum(每一個entry的哈希值). 
     * map的哈希值求法保證了:如果map1.equals(map2)結果為true,則map1.hashCode()=map2.hashCode(), 
     * 當然這樣的設計也符合Object中對hashCode的定義. 
     * @see Map.Entry#hashCode() 
     * @see Object#equals(Object) 
     * @see #equals(Object) 
     */  
    int hashCode();  
  
  
    /*---------以下為預設方法--------*/  
    /** 
     * 傳回指定key對應的value,如果沒有對應的映射,則傳回傳入參數中的預設值defaultValue. 
     * @implSpec 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * @since 1.8 
     */  
    default V getOrDefault(Object key, V defaultValue) {  
        V v;  
        return (((v = get(key)) != null) || containsKey(key))  
                ? v  
                : defaultValue;  
    }  
  
    /** 
     * 對map中每一個entry執行action中定義對操作,直到全部entry執行完成or執行中出現異常為止. 
     * 除非map的實作類有規定,否則forEach的執行順序為entrySet中entry的順序. 
     * 執行中的異常最終抛給方法的調用者. 
     * @implSpec 
     * The default implementation is equivalent to, for this {@code map}: 
     * 本方法的預設實作和下面的代碼是等價的: 
     * for (Map.Entry<K, V> entry : map.entrySet()) 
     *     action.accept(entry.getKey(), entry.getValue()); 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 
     * @since 1.8 
     */  
    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);  
        }  
    }  
  
    /** 
     * 對于map中每一個entry,将其value替換成BiFunction接口傳回的值.直到所有entry替換完or出現異常為止. 
     * 如果執行過程中出現異常,則抛給調用者. 
     * @implSpec 
     * 本方法的預設執行和下面代碼等價: 
     * for (Map.Entry<K, V> entry : map.entrySet()) 
     *     entry.setValue(function.apply(entry.getKey(), entry.getValue())); 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 
     * @since 1.8 
     */  
    default void replaceAll(java.util.function.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);  
            }  
        }  
    }  
  
    /** 
     * 如果指定的鍵尚未與值相關聯(或被映射為null),則将它與給定的值相關聯并傳回null,否則傳回目前值。 
     * @implSpec 
     * 本方法的預設執行和下面的代碼等價: 
     * V v = map.get(key); 
     * if (v == null) 
     *     v = map.put(key, value); 
     * return v; 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 
     * @since 1.8 
     */  
    default V putIfAbsent(K key, V value) {  
        V v = get(key);  
        if (v == null) {  
            v = put(key, value);  
        }  
  
        return v;  
    }  
  
    /** 
     * 如果給定的參數key和value在map中是一個entry,則删除這個entry. 
     * @implSpec 
     * 本方法的預設實作和下面代碼等價: 
     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) { 
     *     map.remove(key); 
     *     return true; 
     * } else 
     *     return false; 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 
     * @since 1.8 
     */  
    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;  
    }  
  
    /** 
     * Replaces the entry for the specified key only if currently 
     * mapped to the specified value. 
     * 如果給定的key和value在map中有entry,則為指定key的entry,用新value替換舊的value. 
     * @implSpec 
     * 本方法的預設實作和下面代碼等價: 
     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) { 
     *     map.put(key, newValue); 
     *     return true; 
     * } else 
     *     return false; 
     * } 
     * 
     * 對于不支援value為null的map來說,如果舊value為null,本方法預設不抛出異常,除非新value也是null. 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * @since 1.8 
     */  
    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;  
    }  
  
    /** 
     * 如果指定key在map中有value,則用參數value進行替換. 
     * 本方法的預設實作和下面代碼等價: 
     * if (map.containsKey(key)) { 
     *     return map.put(key, value); 
     * } else 
     *     return null; 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 
     * @since 1.8 
     */  
    default V replace(K key, V value) {  
        V curValue;  
        if (((curValue = get(key)) != null) || containsKey(key)) {  
            curValue = put(key, value);  
        }  
        return curValue;  
    }  
  
    /** 
     * 如果指定key在map中沒有對應的value,則使用輸入參數,即函數接口mappingfunction為其計算一個value. 
     * 如果計算value不為null,則将value插入map中. 
     * 
     * 如果計算function傳回結果為null,則不插入任何映射.如果函數function本身抛出(非檢查型)異常,則異常會被重新抛出,自然 
     * 也不會插入任何映射. 
     * 最常見的用法是構造一個新的對象作為初始映射值或memoized結果,如下所示: 
     * map.computeIfAbsent(key, k -> new Value(f(k))); 
     * 
     * or是為了實作一個多value的map(如Map<k,Collection<v>>),進而支援一個key對應多個value. 
     * 
     * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v); 
     * }</pre> 
     * 
     * 本方法的預設實作和下面代碼等價: 
     * if (map.get(key) == null) { 
     *     V newValue = mappingFunction.apply(key); 
     *     if (newValue != null) 
     *         map.put(key, newValue); 
     * } 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 特别是,所有ConcurrentMap的子接類,必須給出說明:如果目前value不存在,指派的function操作是否為原子性的. 
     * @since 1.8 
     */  
    default V computeIfAbsent(K key,  
                              java.util.function.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;  
    }  
  
    /** 
     * 如果map中存在指定key對應的value,且不為null,則本方法會嘗試使用function,并利用key生成一個新的value. 
     * 
     * 如果function接口傳回null,map中原entry則被移除.如果function本身抛出異常,則目前map不會發生改變. 
     * 
     * 本方法的預設實作和下面的代碼等價: 
     * if (map.get(key) != null) { 
     *     V oldValue = map.get(key); 
     *     V newValue = remappingFunction.apply(key, oldValue); 
     *     if (newValue != null) 
     *         map.put(key, newValue); 
     *     else 
     *         map.remove(key); 
     * } 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 特别是,所有ConcurrentMap的子接類,必須給出說明:如果目前value不存在,指派的function操作是否為原子性的. 
     * 
     * @since 1.8 
     */  
    default V computeIfPresent(K key,  
                               java.util.function.BiFunction<? super K, ? super V, ? extends V> remappingFunction) {  
        Objects.requireNonNull(remappingFunction);  
        V oldValue;  
        if ((oldValue = get(key)) != null) {  
            V newValue = remappingFunction.apply(key, oldValue);  
            //如果新value不為null,則更新value  
            if (newValue != null) {  
                put(key, newValue);  
                return newValue;  
            }  
            //如果新value為null,則删除map中原entry  
            else {  
                remove(key);  
                return null;  
            }  
        } else {  
            return null;  
        }  
    }  
  
    /** 
     * 利用指定key和value計算一個新映射. 
     * 比如:向一個value映射中新增或者拼接一個String. 
     * 
     * 下面的merge()方法在這樣的用途上面通常使用更友善一些. 
     * 
     * 如果function接口傳回null,則map中原entry被移除(如果本來就不存在,則不執行移除操作). 
     * 如果function本身抛出(非檢查型)異常,異常會被重新抛出,目前map也不會發生改變. 
     * 
     * 本方法的預設實作和下面代碼等價: 
     * V oldValue = map.get(key); 
     * V newValue = remappingFunction.apply(key, oldValue); 
     * if (oldValue != null ) { 
     *    if (newValue != null) 
     *       map.put(key, newValue); 
     *    else 
     *       map.remove(key); 
     * } else { 
     *    if (newValue != null) 
     *       map.put(key, newValue); 
     *    else 
     *       return null; 
     * } 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 特别是,所有ConcurrentMap的子接類,必須給出說明:如果目前value不存在,指派的function操作是否為原子性的. 
     * 
     * @since 1.8 
     */  
    default V compute(K key,  
                      java.util.function.BiFunction<? super K, ? super V, ? extends V> remappingFunction) {  
        Objects.requireNonNull(remappingFunction);  
        //擷取舊value  
        V oldValue = get(key);  
        //利用key和舊value生成新value  
        V newValue = remappingFunction.apply(key, oldValue);  
        //如果新value為null  
        if (newValue == null) {  
            //如果舊value不為null,或者map存在key,則删除舊entry  
            if (oldValue != null || containsKey(key)) {  
                // something to remove  
                remove(key);  
                return null;  
            } else {  
                //什麼也不做  
                return null;  
            }  
        } else {  
            // 添加or覆寫原映射  
            put(key, newValue);  
            return newValue;  
        }  
    }  
  
    /** 
     * 如果指定key沒有value,或者其value為null,則将其改為給定的非null的value. 
     * 否則,用給定的function傳回值替換原value. 
     * 如果給定參數value和function傳回結果都為null,則删除map中這個entry. 
     * 這一方法常用于:對一個key合并多個映射的value時. 
     * 比如:要建立或追加一個String給一個值映射. 
     * 
     * 如果function傳回null,則map中原entry被移除.如果function本身抛出異常,則異常會被重新抛出,且 
     * 目前map不會發生更改. 
     * 
     * 本方法的預設實作和下面代碼等價,傳回結果為目前value或者null 
     * V oldValue = map.get(key); 
     * V newValue = (oldValue == null) ? value : 
     *              remappingFunction.apply(oldValue, value); 
     * if (newValue == null) 
     *     map.remove(key); 
     * else 
     *     map.put(key, newValue); 
     * } 
     * 
     * 此預設方法對于線程同步和執行過程的原子性并不能保證. 
     * 任何實施提供原子性保證必須重寫此方法并記錄其方法. 
     * 特别是,所有ConcurrentMap的子接類,必須給出說明:如果目前value不存在,指派的function操作是否為原子性的 
     * 
     * @since 1.8 
     */  
    default V merge(K key, V value,  
                    BiFunction<? super V, ? super V, ? extends V> remappingFunction) {  
        Objects.requireNonNull(remappingFunction);  
        Objects.requireNonNull(value);  
        //擷取舊value  
        V oldValue = get(key);  
        //如果舊value為null,則newValue=參數value;  
        //如果舊value不為null,則newValue=function接口傳回值  
        V newValue = (oldValue == null) ? value :  
                remappingFunction.apply(oldValue, value);  
        //如果newValue=null,則删除map中的entry,說明參數value=null或者function接口傳回值為null  
        if(newValue == null) {  
            remove(key);  
        }  
        //否則,為原entry插入新value.  
        else {  
            put(key, newValue);  
        }  
        //傳回新value  
        return newValue;  
    }  
}  
           

參考:https://blog.csdn.net/caoxiaohong1005/article/category/7278825

繼續閱讀