Java中的Map【二】SortedMap接口

        所使用的jdk版本爲1.8版本,先看一下SortedMap在JDK中Map的UML類圖中的位置:

2.1.2 SortedMap接口

       SortedMap<K,V>繼承Map<K,V>接口,是一個更進一步提供基於鍵key的總體排序的 Map。該映射是根據其鍵key的自然順序(自然排序的定義可以參見java.lang.Comparable接口,就是實現該接口)進行排序的,或者根據通常在創建有序映射SortedMap時提供的 Comparator 進行排序。

       插入有序映射的所有鍵都必須實現Comparable接口(或者被指定的比較器Comparator接受)。另外,所有這些鍵都必須是可互相比較的:對有序映射中的任意兩個鍵k1和k2,執行k1.compareTo(k2)(或comparator.compare(k1, k2))都不得拋出ClassCastException。試圖違反此限制將導致有問題的的方法或者構造方法調用拋出ClassCastException。

       SortedMap<K,V>接口從定義來看比較簡單,需要注意的就是其中的key要麼實現Comparable接口要麼被指定的比較器Comparator接受。接口定義描述建議所有的SortedMap實現類都應該提供四個標準的構造函數:

(1)void 無參的構造函數,此時按照鍵的自然順序進行排序;

(2)只有一個 Comparator 類型參數的構造方法,它創建一個空的有序映射,並且根據指定的 Comparator進行排序;

(3)只有一個 Map 類型參數的構造方法,它創建一個新的有序映射,其鍵-值映射關係與參數Map相同,按照鍵的自然順序進行排序;

(4)只有一個 SortedMap 類型參數的構造方法,它創建一個新的有序映射,其鍵-值映射關係和排序方法與入參的SortedMap相同。

因爲接口中無法定義構造方法,無法保證以上四種方法一定就會被實現。最上面的圖,SortedMap實現類TreeMap是全部實現了這四個構造方法的。

因爲SortedMap定義相對簡單,簡單列一些裏面的函數:

public interface SortedMap<K,V> extends Map<K,V> {
    /**
     * 返回對此映射中的鍵進行排序的比較器;如果使用的自然順序,返回null
     */
    Comparator<? super K> comparator();

    /**
     * 返回此映射的部分視圖,其鍵值的範圍從 fromKey(包括)到 toKey(不包括)。(如果 fromKey 
     * 和 toKey 相等,則返回映射爲空。)返回的映射受此映射支持,所以在返回映射中的更改將反映在此 
     * 映射中,反之亦然。返回的映射支持此映射支持的所有可選映射操作。
     * 如果試圖在返回映射的範圍之外插入鍵,則返回的映射將拋出 IllegalArgumentException。
     *
     * @param fromKey - 返回映射中key的低端點(包括)
     * @param toKey - 返回映射中鍵的高端點(不包括)
     * @return 此映射的部分視圖,其鍵值的範圍從 fromKey(包括)到 toKey(不包括)
     * @throws ClassCastException - 如果無法使用此映射的比較器(如果此映射沒有比較器,則使用 
     * 自然順序)比較 fromKey 和 toKey。如果 fromKey 或 toKey 不能與映射中當前鍵進行比較,則 
     * 實現可以(但不是必須)拋出此異常。
     * @throws NullPointerException - 如果 fromKey 或 toKey 爲 null,並且此映射不允許使 
     * 用 null 鍵
     * @throws IllegalArgumentException - 如果 fromKey 大於 toKey;如果此映射本身有範圍限 
     * 制,並且 fromKey 或 toKey 位於範圍的邊界之外
     */
    SortedMap<K,V> subMap(K fromKey, K toKey);

    /**
     * 返回此映射的部分視圖,其鍵值嚴格小於 toKey。返回的映射受此映射支持,所以在返回映射中的更改 
     * 將反映在映射中,反之亦然。返回的映射支持此映射支持的所有可選映射操作。
     *
     * 如果試圖在返回映射的範圍之外插入鍵,則返回的映射將拋出 IllegalArgumentException。
     *
     * @param toKey 返回映射視圖中鍵的高端點(不包括)
     * @return 此映射的部分視圖,且其中的鍵嚴格小於 toKey
     * @throws ClassCastException 如果 toKey 與此映射的比較器不兼容(或者,如果該映射沒有比 
     * 較器, 如果 toKey 沒有實現 Comparable)。如果 toKey 不能與映射中的當前鍵進行比較,則實 
     * 現可以(但不是必須)拋出此異常。
     * @throws NullPointerException 如果toKey爲null,且該映射不允許key爲null
     * @throws IllegalArgumentException 如果此映射本身有範圍限制,並且 toKey 位於範圍的邊界 
     * 之外
     */
    SortedMap<K,V> headMap(K toKey);

    /**
     * 返回此映射的部分視圖,其鍵大於等於 fromKey。返回的映射受此映射支持,所以在返回映射中的更改 
     * 將反映在映射中,反之亦然。返回的映射支持此映射支持的所有可選映射操作。
     * 如果試圖在返回映射的範圍之外插入鍵,則返回的映射將拋出 IllegalArgumentException。
     *
     * @param fromKey 返回映射中鍵的低端點(包括)
     * @return 此映射的部分視圖,其中的鍵大於等於 fromKey
     * @throws ClassCastException 如果 fromKey 與此映射的比較器不兼容(或者,如果該映射沒有 
     * 比較器;如果 fromKey 沒有實現 Comparable)。如果 fromKey 不能與映射中的當前鍵進行比 
     * 較,則實現可以(但不是必須)拋出此異常。
     * @throws NullPointerException 如果 fromKey 爲 null,並且此映射不允許使用 null 鍵
     * @throws IllegalArgumentException 如果此映射本身有範圍限制,並且 fromKey 位於範圍的 
     * 邊界之外
     */
    SortedMap<K,V> tailMap(K fromKey);

    /**
     * 返回此映射中當前第一個(最低)鍵。
     *
     * @return 返回此映射中當前第一個(最低)鍵。
     * @throws NoSuchElementException 如果map爲空(即size() == 0)
     */
    K firstKey();

    /**
     * 返回映射中當前最後一個(最高)鍵。
     *
     * @return 返回映射中當前最後一個(最高)鍵。
     * @throws NoSuchElementException 如果map爲空(即size() == 0)
     */
    K lastKey();

    /**
     * 與父接口Map中的定義一樣,但有順序
     */
    Set<K> keySet();

    /**
     * 與父接口Map中的定義一樣,但有順序(根據key的順序)
     */
    Collection<V> values();

    /**
     * 與父接口Map中的定義一樣,但有順序(根據key的順序)
     */
    Set<Map.Entry<K, V>> entrySet();
}

需要注意的地方:

1、subMap(K fromKey, K toKey)、headMap(K toKey)、tailMap(K fromKey),都是滿足fromKey <= key < toKey;

2、firstKey()和lastKey()方法,當SortedMap對象爲空(size() == 0)就會拋出NoSuchElementException異常;

3、subMap等子集map和當前sortedMap的元素變更是互相影響的。

以上注意點可以用TreeMap實現驗證(後續會分析在TreeMap中的實現):

public static void main(String[] args) {
        SortedMap<Integer, Integer> sortedMap = new TreeMap();
        sortedMap.put(2,2);
        sortedMap.put(4,4);
        sortedMap.put(1,1);
        System.out.println(sortedMap.subMap(1,2));
        System.out.println(sortedMap.headMap(2));
        System.out.println(sortedMap.tailMap(2));
        //獲取的子集中添加一個元素會影響當前sortedMap
        SortedMap<Integer, Integer> subSortedMap = sortedMap.subMap(0,4);
        subSortedMap.put(3,3);
        //當前sortedMap增減元素會影響子集subSortedMap
        sortedMap.put(0,0);
        System.out.println(subSortedMap);
        System.out.println(sortedMap);
    }

 程序輸出結果:

{1=1}
{1=1}
{2=2, 4=4}
{0=0, 1=1, 2=2, 3=3}
{0=0, 1=1, 2=2, 3=3, 4=4}

以上,SortedMap<K,V>暫時寫這麼多~

 

題外話:這裏發現一個值得玩味的地方,就是keySet()、values()、entrySet()三個方法在父接口Map已經有相同結構的方法定義了,在SortedMap中又重新定義了一次(不過返回的都是有順序的)。JDK中還有很多類似這樣子接口重新定義了父接口中方法情況,比如List接口中定義了和父接口Collection一樣的size()、isEmpty()等,感覺這種更多是處於軟件工程和設計模式等方面的考慮吧,不知諸位對此有何看法,歡迎留言賜教~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章