第一次寫筆記就從map開始吧,如上圖所示,綠色的是interface,黃色的是abstract class,藍色的是class,可以看出所有和圖相關的接口,抽象類和類的起源都是interface map<K,V>。現在看一下當前Map接口中實現了什么,里面包含了一個內部接口interface Entry<K,V>,聲明了14個方法,同時還定義了11個方法(在jdk1.8中,在interface中可以使用default關鍵字來定義完整的方法)
由於聲明的方法都是原來版本jdk已經存在的,比較簡單,所以我們從聲明的方法開始介紹
1 public interface Map<K, V> { 2 3 /** 4 * 方法返回鍵值對個數,當鍵值對個數大於Integer.MAX_VALUE 5 * 時返回Integer.MAX_VALUE 6 */ 7 int size(); 8 9 /** 10 * 當Map中沒有鍵值對的時候,返回true 11 */ 12 boolean isEmpty(); 13 14 /** 15 * 當Map中的鍵包含key的時候返回true,相當於執行了如下語句 16 * key==null ? k==null : key.equals(k) 17 * 此處應該注意Map中的鍵是可以為null的,但是只可以有一個 18 * 需要注意的是本方法會有兩個異常 19 * ClassCastException當傳入的key和本Map中設置的key類型不相容的時候 20 * NullPointerException當傳入的key==null,並且Map中的鍵沒有null的時候 21 */ 22 boolean containsKey(Object key); 23 24 /** 25 * 當有多於一個key的value等於傳入的value時會返回true 26 * 相當於執行value==null ? v==null : value.equals(v) 27 * 可見value也是可以為null的 28 * 需要注意的是本方法會拋出兩個異常 29 * ClassCastException當傳入的值和Map中的值不相容的時候 30 * NullPointerException當value中沒有一個值為null的時候 31 */ 32 boolean containsValue(Object value); 33 34 /** 35 * 如果當前的key存在於Map中,會返回對應的value,否則會返回null 36 * 需要注意的是本方法會有兩個異常 37 * ClassCastException當傳入的key和本Map中設置的key類型不相容的時候 38 * NullPointerException當傳入的key==null,並且Map中的鍵沒有null的時候 39 * 40 */ 41 V get(Object key); 42 43 /** 44 * 當key不存在是會放入新的鍵值對,當key存在時,會更新key對應的value值 45 * 本方法會產生四個異常 46 * UnsupportedOperationException當Map不支持put操作的時候 47 * ClassCastException當key或者value不相容的時候 48 * NullPointerException當Map不允許key或者value為null的時候 49 * IllegalArgumentException如果指定鍵或值的某些屬性阻止將其存儲在此映射中 50 */ 51 V put(K key, V value); 52 53 /** 54 * 當Map中有這個key的時候,會返回相應的value,否則會返回null 55 * 本方法會拋出三個異常 56 * UnsupportedOperationException當Map不支持此操作時 57 * ClassCastException當key的類型不相容時 58 * NullPointerException當key是null並且這個Map不允許key為null時 59 */ 60 V remove(Object key); 61 62 /** 63 * 將一個Map的所有鍵值對放入本Map,對於每一個鍵值對都調用的是put(K key, V value)方法 64 * 本方法會產生四個異常 65 * UnsupportedOperationException當Map不支持put操作的時候 66 * ClassCastException當key或者value不相容的時候 67 * NullPointerException當Map不允許key或者value為null的時候 68 * IllegalArgumentException如果指定鍵或值的某些屬性阻止將其存儲在此映射中 69 */ 70 void putAll(Map<? extends K, ? extends V> m); 71 72 /** 73 * 從Map中移除所有的元素 74 * 會拋出一個異常 75 * UnsupportedOperationException當Map不支持本操作的時候 76 */ 77 void clear(); 78 79 /** 80 * 會以集合的形式返回key,當修改Map的key時會反應在Set中,反之亦然 81 */ 82 Set<K> keySet(); 83 84 /** 85 * 返回一個Collection集合對於值來說,因為值可以有重復的,所以才選用了Collection 86 * 同樣的對Map修改時,也會反應到Collection上 87 */ 88 Collection<V> values(); 89 90 /** 91 * 返回一個鍵值對的集合Entry<K, V> 92 */ 93 Set<Map.Entry<K, V>> entrySet(); 94 95 /** 96 * 本方法是用來比較兩個Map是否相同的 97 */ 98 boolean equals(Object o); 99 100 /** 101 * 本方法是用於返回一個Map的Hash值,本方法要求對Map中的每一個Entry<K,V>進行運算的 102 * 這樣保證了當m1.equals(m2)時m1.hashCode()==m2.hashCode() 103 */ 104 int hashCode(); 105 106 107 }
接下來我們來看一下內部的接口interface Entry<K,V>的內容
1 interface Entry<K,V> { 2 /** 3 * 返回Entry的key 4 * IllegalStateException 並不要求實現類必須拋出這個異常,在訪問Map中的Entry元素時可能用到,即Entry已經被移除時 5 */ 6 K getKey(); 7 8 /** 9 * 返回Entry的value 10 * IllegalStateException 並不要求實現類必須拋出這個異常,在訪問Map中的Entry元素時可能用到,即Entry已經被移除時 11 */ 12 V getValue(); 13 14 /** 15 * 重新設置Entry的value,但是當映射關系被移除時,該方法的行為還未被定義 16 * 拋出五個異常 17 * UnsupportedOperationException如果Map不支持put操作 18 * ClassCastException當與指定類型不相容的時候 19 * NullPointerException當Map不允許出現null而此時設置的值為null的時候 20 * IllegalArgumentException如果當前值的屬性不允許它存儲在圖中 21 * IllegalStateException並不要求實現類必須拋出這個異常,在訪問Map中的Entry元素時可能用到,即Entry已經被移除時 22 */ 23 V setValue(V value); 24 25 /** 26 * 當比較對象也是一個Entry並且表達同樣的映射關系的時候返回true 27 */ 28 boolean equals(Object o); 29 30 /** 31 * 本方法實現的要求是當e1.equals(e2)時,e1.hashCode()==e2.hashCode() 32 */ 33 int hashCode(); 34 35 //從以下開始都是jdk1.8新增的方法,對於jdk1.8的新特性就不再這里分析了,會單寫一篇的 36 /** 37 * 本方法會返回一個比較器,用來實現對Entry的key進行比較 38 */ 39 public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() { 40 return (Comparator<Map.Entry<K, V>> & Serializable) 41 (c1, c2) -> c1.getKey().compareTo(c2.getKey()); 42 } 43 44 /** 45 * 本方法返回一個比較器,用來實現對Entry的value進行比較,這里表示返回值同時滿足兩個接口 46 */ 47 public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() { 48 return (Comparator<Map.Entry<K, V>> & Serializable) 49 (c1, c2) -> c1.getValue().compareTo(c2.getValue()); 50 } 51 52 /** 53 * 這個方法和上兩個方法不同之處在於上兩個要求K或者V實現Comparable接口,使得本身可以比較 54 * 而這個方法中並沒有對K,V有什么要求,而是需要一個已經實現Comparator的接口 55 */ 56 public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) { 57 Objects.requireNonNull(cmp); 58 return (Comparator<Map.Entry<K, V>> & Serializable) 59 (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); 60 } 61 62 /** 63 * 同上 64 */ 65 public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) { 66 Objects.requireNonNull(cmp); 67 return (Comparator<Map.Entry<K, V>> & Serializable) 68 (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); 69 } 70 71 }
這里簡單解釋一下上述代碼中jdk1.8的新特性以便使代碼容易理解一些,Comparator<Map.Entry<K, V>> & Serializable這里並不是表達與操作,而是返回值同時實現了這兩個接口,(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue())是lambda表達式實現了一個函數式接口Comparator的compare方法
最后一部分是Map在jdk1.8中新增的default方法,在jdk1.8中,可以在interface中實現方法了,但是得用default關鍵字修飾
1 /** 2 * 本方法是在普通get方法上增加了一個默認值,防止了得到的value為null的情況 3 * 拋出兩個異常 4 * ClassCastException當key和Map中要求的key不兼容時 5 * NullPointerException當Map不支持null為key時 6 */ 7 default V getOrDefault(Object key, V defaultValue) { 8 V v; 9 return (((v = get(key)) != null) || containsKey(key)) 10 ? v 11 : defaultValue; 12 } 13 14 /** 15 * 對Map中的每一個Entry進行一次action包含的操作 16 * 拋出兩個異常 17 * NullPointerException當action為null時 18 * ConcurrentModificationException在迭代過程中有元素被移除 19 */ 20 default void forEach(BiConsumer<? super K, ? super V> action) { 21 Objects.requireNonNull(action); 22 for (Map.Entry<K, V> entry : entrySet()) { 23 K k; 24 V v; 25 try { 26 k = entry.getKey(); 27 v = entry.getValue(); 28 } catch(IllegalStateException ise) { 29 // this usually means the entry is no longer in the map. 30 throw new ConcurrentModificationException(ise); 31 } 32 action.accept(k, v); 33 } 34 } 35 36 /** 37 * 對Map中的每個Entry都用function進行操作,返回得到的結果重新設置value 38 */ 39 default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { 40 Objects.requireNonNull(function); 41 for (Map.Entry<K, V> entry : entrySet()) { 42 K k; 43 V v; 44 try { 45 k = entry.getKey(); 46 v = entry.getValue(); 47 } catch(IllegalStateException ise) { 48 // this usually means the entry is no longer in the map. 49 throw new ConcurrentModificationException(ise); 50 } 51 52 // ise thrown from function is not a cme. 53 v = function.apply(k, v); 54 55 try { 56 entry.setValue(v); 57 } catch(IllegalStateException ise) { 58 // this usually means the entry is no longer in the map. 59 throw new ConcurrentModificationException(ise); 60 } 61 } 62 } 63 64 /** 65 * 當key對應的value為null的時候,設置新的value值 66 */ 67 default V putIfAbsent(K key, V value) { 68 V v = get(key); 69 if (v == null) { 70 v = put(key, value); 71 } 72 73 return v; 74 } 75 76 /** 77 * 當key和value與當前map中有完全相同的,就刪除該元素,返回true,否則返回false,不做任何操作 78 */ 79 default boolean remove(Object key, Object value) { 80 Object curValue = get(key); 81 if (!Objects.equals(curValue, value) || 82 (curValue == null && !containsKey(key))) { 83 return false; 84 } 85 remove(key); 86 return true; 87 } 88 89 /** 90 * 當Map中存在key->oldValue時,替換為key->newValue,返回true,否則返回false,不做任何操作 91 */ 92 default boolean replace(K key, V oldValue, V newValue) { 93 Object curValue = get(key); 94 if (!Objects.equals(curValue, oldValue) || 95 (curValue == null && !containsKey(key))) { 96 return false; 97 } 98 put(key, newValue); 99 return true; 100 } 101 102 /** 103 * 用新的value替換老的value,並返回老的value,如果key不存在,返回null 104 */ 105 default V replace(K key, V value) { 106 V curValue; 107 if (((curValue = get(key)) != null) || containsKey(key)) { 108 curValue = put(key, value); 109 } 110 return curValue; 111 } 112 113 /** 114 * 傳入一個單參數函數,找到key對應的value,如果value==null,然后對key進行重新計算,得到新的value,返回新的value。否則返回null 115 */ 116 default V computeIfAbsent(K key, 117 Function<? super K, ? extends V> mappingFunction) { 118 Objects.requireNonNull(mappingFunction); 119 V v; 120 if ((v = get(key)) == null) { 121 V newValue; 122 if ((newValue = mappingFunction.apply(key)) != null) { 123 put(key, newValue); 124 return newValue; 125 } 126 } 127 128 return v; 129 } 130 131 /** 132 * 如果Map中存在key,並且對應的value!=null的時候,用傳入的兩個參數的函數進行重新計算,得到新的value,如果新的value==null 133 * 就刪除這個鍵值對,返回null,否則覆蓋舊值,返回新的value,如果key不存在,也返回null 134 */ 135 default V computeIfPresent(K key, 136 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 137 Objects.requireNonNull(remappingFunction); 138 V oldValue; 139 if ((oldValue = get(key)) != null) { 140 V newValue = remappingFunction.apply(key, oldValue); 141 if (newValue != null) { 142 put(key, newValue); 143 return newValue; 144 } else { 145 remove(key); 146 return null; 147 } 148 } else { 149 return null; 150 } 151 } 152 153 /** 154 * 通過原來的鍵值對,計算出一個新的值,如果新的值不為空,重新設置鍵值對,並返回新的value,否則刪除原來的鍵值對,返回null 155 */ 156 default V compute(K key, 157 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 158 Objects.requireNonNull(remappingFunction); 159 V oldValue = get(key); 160 161 V newValue = remappingFunction.apply(key, oldValue); 162 if (newValue == null) { 163 // delete mapping 164 if (oldValue != null || containsKey(key)) { 165 // something to remove 166 remove(key); 167 return null; 168 } else { 169 // nothing to do. Leave things as they were. 170 return null; 171 } 172 } else { 173 // add or replace old mapping 174 put(key, newValue); 175 return newValue; 176 } 177 } 178 179 /** 180 * 將舊的value和新的value進行混合計算,得到另一個value,如果這個value不為空,就和原來的key形成映射關系,返回新的value, 181 * 否則移除原來的鍵值對,返回null 182 */ 183 default V merge(K key, V value, 184 BiFunction<? super V, ? super V, ? extends V> remappingFunction) { 185 Objects.requireNonNull(remappingFunction); 186 Objects.requireNonNull(value); 187 V oldValue = get(key); 188 V newValue = (oldValue == null) ? value : 189 remappingFunction.apply(oldValue, value); 190 if(newValue == null) { 191 remove(key); 192 } else { 193 put(key, newValue); 194 } 195 return newValue; 196 }
這些方法中出現了比較陌生的BiConsumer,BiFunction和Function這三個接口,都是在java.util.function包下的新接口,可以把他們看做一個函數去理解就好了。BiConsumer
是接受兩個參數,沒有計算的返回值。BiFunction是接受兩個參數返回一個參數。Function是接受一個參數返回一個參數。