吃透Java集合系列八:Map

文章首發(fā)csdn博客地址:https://blog.csdn.net/u013277209?viewmode=contents

Map接口分析

關(guān)于Map接口谴返,JDK是這樣描述的:

  • Map是一個有鍵值對映射的對象嫉到,map不能包含相同的key,每一個key至多能映射一個value。
  • Map替代了Dictionary這個類,Dictionary是抽象類而非接口,替代原因:接口總是優(yōu)于抽象類锅纺。
  • Map接口提供了3個集合視圖,包括:keys的set集合肋殴, values的集合;囤锉,key-value的set集合坦弟,注意:values集合不是set類型,因為value可相同。
  • Map返回元素的順序官地,取決于map對應(yīng)的某個集合視圖迭代器的順序酿傍,一些map的實現(xiàn),比如TreeMap類驱入,對于map返回元素的順序有特殊的規(guī)定赤炒,其它的map實現(xiàn)類,比如HashMap類,就沒有特殊的規(guī)定。
  • 不要把異變的對象作為Map的key亏较,如果map中的一個key發(fā)生了改變莺褒,并且影響了equals()方法的使用,那么map并不會提示我們雪情。
  • 所有的通用map實現(xiàn)類都應(yīng)該提供兩個"標準"的構(gòu)造器函數(shù)遵岩,一個是無參且返回類型為void的函數(shù),另一個就是僅含有一個參數(shù)且類型為map類型的的構(gòu)造方法,這個方法會使用其參數(shù)構(gòu)造一個新的map巡通,且新的map和參數(shù)map有相同的key和value尘执,但是,map接口這里沒辦法強制執(zhí)行這一建議(因為接口里面不能包含構(gòu)造器函數(shù))宴凉,不過JDK里面所有通用的map實現(xiàn)類都是符合這一點要求的誊锭。
  • 一些map的實現(xiàn)類在key和value的取值上面會有一些規(guī)定,比如弥锄,一些map實現(xiàn)類不允許key或者value為null丧靡。
  • map接口是java集合框架中的一個成員。
  • 集合框架接口定義了很多種和equals()方法相關(guān)的實現(xiàn)籽暇,比如,containsKey()方法窘行,當前僅當map包含了鍵k的定義是:key = = null ? k == null : key.equals(k),這一規(guī)范的寫法图仓,不能被理解為為:如果調(diào)用方法使用的是一個非null參數(shù)的話,然后只是再調(diào)用key.equals(k)方法就可以了罐盔,具體實現(xiàn)可以通過避免調(diào)用equals()方法來實現(xiàn)優(yōu)化,比如救崔,可以先比較兩個key的哈希值惶看,(哈希值保證了,如果兩個對象的哈希值都不相同六孵,那么這兩個對象肯定不會相同)纬黎,更一般的情況是,大量集合框架接口的實現(xiàn)類可以充分利用底層對象(Object)的方法的優(yōu)勢劫窒,只要實現(xiàn)者認為他們這么做是合理的本今。
public interface Map<K,V> {
    //增
    /**
     * put方法是將指定的key-value存儲到map里面的操作.如果map之前包含了一個此key對應(yīng)的映射,
     * 那么此key對應(yīng)的舊value值會被新的value值替換.
     */
    V put(K key, V value);
    /**
     * putAll方法是將一個指定map的映射拷貝到當前map.這一操作類似于將指定map的key-value對通過put方法一個個拷貝過來。
     * 在拷貝過程中,如果指定的這個map被更改了,那么這時候會出現(xiàn)什么情況,并不清楚。
     */
    void putAll(Map<? extends K, ? extends V> m);
    
    //刪
    /**
     * remove方法用于移除map中已有的某個key.更一般的講,如果map包含了一個滿足條件key==null ?  k==null : key.equals(k)的映射,
     * 這一映射就會被移除.(map最多包含一個這樣的映射)
     * 本方法會返回移除的key對應(yīng)的value值,如果map這個key沒有對應(yīng)的value值,則返回null冠息。
     * 如果map允許null值,那么返回null值并不一定表明map不包含對應(yīng)key的映射值;因為這也可能是key本身對應(yīng)的value值就是null.
     */
    V remove(Object key);
    /**
     * 移除map中所有的映射
     */
    void clear();

    //查
    /**
     * 返回map中key-value映射的個數(shù).如果map包含的key-value個數(shù)超過了Integer.MAX_VALUE這個數(shù)
     * 則返回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接口的實現(xiàn)類中,這一操作都需要map大小的線性時間來完成.
     */
    boolean containsValue(Object value);

    /**
     * 返回指定key映射的value.如果map沒有指定的key,則返回null.
     */
    V get(Object key);

    //三個返回key挪凑,value,key-value的集合
    /**
     * 此方法:返回map包含所有的key的一個set集合視圖
     */
    Set<K> keySet();
    /**
     * values方法返回map內(nèi)存儲的所有值的集合(畢竟值集合中,值可以有重復(fù)的,所以此方法和上面的返回的
     * key集合的結(jié)果類型不一樣,因為key肯定都是不同的).
     */
    Collection<V> values();

    /**
     * 此方法返回map里存儲的所有映射的視圖.
     */
    Set<Map.Entry<K, V>> entrySet();

    //兩個覆蓋object的方法
     /**
     * 用于對比兩個map是否相等.
     * 如果給定的對象是一個map且兩個map的映射一致,則返回true.
     * 一般,兩個map的映射一致,要滿足的條件是:m1.entrySet().equals(m2.entrySet())
     * 這就保證了實現(xiàn)了map接口的不同類對于equals方法的使用才是正確的.
     */
    boolean equals(Object o);

    /**
     * 返回map的哈希值逛艰,map的哈希值被定義為:這個map的entrySet視圖的每一個條目的哈希值的總和.
     * 這就保證了任意兩個map相等,則他們的哈希值一定相等,這也是Object類對哈希值的普遍要求(哈希值作為兩個對象相等的必要非充分條件).
     */
    int hashCode();

    /**
     * map條目(key-value對),Map.entrySet方法返回的就是map的集合視圖,map視圖中的元素就是來源于此類.
     * 獲取map條目的唯一方式就是來源于集合視圖的迭代器.只有在迭代的過程中,Map.Entry對象才是有效的;
     * 通常,如果通過迭代器獲得的map條目,在遍歷過程中,作為后臺支持的map被修改了,那么map條目會如何被影響,對此
     * 并沒有做出具體規(guī)定(當然此處說的map修改不包括setValue方法的調(diào)用).
     */
    interface Entry<K,V> {
        /**
         * 獲取當前map條目對應(yīng)的key
         */
        K getKey();

        /**
         * 返回map條目對應(yīng)的value值.
         */
        V getValue();

        /**
         * 用指定值替換當前條目中的value
         */
        V setValue(V value);

        /**
         * 將指定對象和當前條目做比較,如果給定的對象是一個條目并且兩個條目代表同一個映射,則返回true.
         */
        boolean equals(Object o);

        /**
         * 返回map條目的哈希值
         */
        int hashCode();

        /**
         * 返回一個比較map.entry的比較器,按照key的自然順序排序躏碳,返回的比較器支持序列化
         * @since 1.8
         */
        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());
        }

        /**
         * 返回一個map.enty的比較器,按照value的自然順序排序,返回的比較器支持序列化
         * @since 1.8
         */
        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.entry的比較器,根據(jù)傳入比較器對key排序散怖,如果傳入的比較器支持序列化,則返回的結(jié)果比較器也支持序列化.
         * @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的比較器,根據(jù)傳入比較器對value排序菇绵,如果傳入的比較器支持序列化,則返回的結(jié)果比較器也支持序列化
         * @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());
        }
    }

    
    //1.8新增
    /**
     * 返回指定key對應(yīng)的value,如果沒有對應(yīng)的映射,則返回傳入?yún)?shù)中的默認值defaultValue
     * @since 1.8
     */
    default V getOrDefault(Object key, V defaultValue) {
        V v;
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }

    /**
     * 對map中每一個entry執(zhí)行action中定義對操作,直到全部entry執(zhí)行完成or執(zhí)行中出現(xiàn)異常為止
     * @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出現(xiàn)異常為止
     * @since 1.8
     */
    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);
            }
        }
    }

    /**
     * 如果指定的鍵尚未與值相關(guān)聯(lián)(或被映射為null),則將它與給定的值相關(guān)聯(lián)并返回null,否則返回當前值镇眷。
     * @since 1.8
     */
    default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }

        return v;
    }

    /**
     * 如果給定的參數(shù)key和value在map中是一個entry,則刪除這個entry.
     * @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;
    }

    /**
     * 如果給定的key和value在map中有entry,則為指定key的entry,用新value替換舊的value
     * @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,則用參數(shù)value進行替換
     * @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中沒有對應(yīng)的value,則使用輸入?yún)?shù),即函數(shù)接口mappingfunction為其計算一個value.
     * 如果計算value不為null,則將value插入map中咬最,如果計算function返回結(jié)果為null,則不插入任何映射。
     * @since 1.8
     */
    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;
    }

    /**
     * 如果map中存在指定key對應(yīng)的value,且不為null,則本方法會嘗試使用function,并利用key生成一個新的value
     * 如果function接口返回null,map中原entry則被移除.如果function本身拋出異常,則當前map不會發(fā)生改變.
     * @since 1.8
     */
    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;
        }
    }

    /**
     * 利用指定key和value計算一個新映射欠动,比如:向一個value映射中新增或者拼接一個String丹诀。
     * 如果function接口返回null,則map中原entry被移除(如果本來就不存在,則不執(zhí)行移除操作).
     * 如果function本身拋出(非檢查型)異常,異常會被重新拋出,當前map也不會發(fā)生改變.
     * @since 1.8
     */
    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;
        }
    }

    /**
     * 如果指定key沒有value,或者其value為null,則將其改為給定的非null的value
     * 否則,用給定的function返回值替換原value.
     * 如果給定參數(shù)value和function返回結(jié)果都為null,則刪除map中這個entry.
     * 這一方法常用于:對一個key合并多個映射的value時.
     * 比如:要創(chuàng)建或追加一個String給一個值映射.
     * 如果function返回null,則map中原entry被移除.如果function本身拋出異常,則異常會被重新拋出,且當前map不會發(fā)生更改.
     * @since 1.8
     */
    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;
    }
}
    
}

上述注釋按照JDK進行翻譯,如有不正確支出翁垂,望提出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末硝桩,一起剝皮案震驚了整個濱河市沿猜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碗脊,老刑警劉巖啼肩,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異衙伶,居然都是意外死亡祈坠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門矢劲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赦拘,“玉大人,你說我怎么就攤上這事芬沉⊥汲铮” “怎么了钧唐?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我驱犹,道長,這世上最難降的妖魔是什么灵寺? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任诫尽,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涛救。我一直安慰自己畏邢,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布州叠。 她就那樣靜靜地躺著棵红,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咧栗。 梳的紋絲不亂的頭發(fā)上逆甜,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音致板,去河邊找鬼交煞。 笑死,一個胖子當著我的面吹牛斟或,可吹牛的內(nèi)容都是我干的素征。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼萝挤,長吁一口氣:“原來是場噩夢啊……” “哼御毅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怜珍,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤端蛆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酥泛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體今豆,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年柔袁,在試婚紗的時候發(fā)現(xiàn)自己被綠了呆躲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡捶索,死狀恐怖插掂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腥例,我是刑警寧澤燥筷,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站院崇,受9級特大地震影響肆氓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜底瓣,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一谢揪、第九天 我趴在偏房一處隱蔽的房頂上張望蕉陋。 院中可真熱鬧,春花似錦拨扶、人聲如沸凳鬓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缩举。三九已至,卻和暖如春匹颤,著一層夾襖步出監(jiān)牢的瞬間仅孩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工印蓖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辽慕,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓赦肃,卻偏偏與公主長得像溅蛉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子他宛,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 去公司培訓(xùn)的一天船侧,發(fā)現(xiàn)自己好多培訓(xùn)過的知識都忘記了,溫故而知新了厅各,學(xué)習(xí)還是要不斷的復(fù)習(xí)才可以镜撩。 凱哥今天發(fā)了新歌,...
    你的小鬼啊閱讀 205評論 0 0
  • 通向夢的路那么長 在路途中步履沉重 也曾墮入長夜 也曾置身荒蕪 夢想破碎的聲音擲地有聲 多數(shù)人深夜努力看清當初的夢...
    格裳都欤花開丶閱讀 292評論 0 4
  • 上的電風(fēng)扇電風(fēng)扇發(fā)射點發(fā)射點發(fā)發(fā)是發(fā)打發(fā)士大夫撒旦發(fā)生的撒旦飛灑發(fā)阿斯蒂芬暗室逢燈撒士大夫撒地方啊士大夫撒旦發(fā)生發(fā)...
    體育圈快報閱讀 1,602評論 0 0