Java——Map


Map(java.util.Map)

Map是Java頂層接口之一。

1. 接口注釋大意

將鍵映射到值的對象。Map不能包含重復的鍵;每個鍵最多可以映射到一個值。

該接口代替了Dictionary類,該接口的功能是一個完全抽象的類,而不只是一個單純接口。

Map接口提供了三個集合的實現,這些集合允許將實現的內容視為一組鍵,一組值或是一組鍵-值對映射。映射順序指映射的集合上迭代器返回元素時按照一定的順序。某些Map實現(例如TreeMap類)對它們的順序做出特定的保證,其他的(例如HashMap類)則沒有。

一個可變對象(自己所定義的對象)不能作為Map的鍵,當可變對象作為鍵的時候,如果更改對象的值之后,在eqauls的時候會出現映射的問題;另外就是Map本身不能作為鍵,此種情況不能有效的定義equals和hashcode,但是Map本身是可以作為值存在的。

任何Map的實現類都應該具有兩個構造參數,一個是無參數的構造函數,這個構造函數用於創建一個空的Map對象;一個是具有Map類型的單個參數的構造參數,創建一個與參數類型相同的Map,其實參數類型可以是任何類型的Map。

另外關於一些什么是可選性異常,很多方法是根據根據equals制定的,還要就是自己指向自己的問題的描述。

2. 源碼

1 public interface Map<K,V>{}

Map是一個頂層接口,沒有繼承任何其余接口。

2.1 查詢操作(Query Operations)

1 int size();
2 boolean isEmpty();
3 boolean containsKey(Object key);
4 boolean containsValue(Object value);
5 V get(Object key);
6 V put(K key, V value);
7 V remove(Object key);

2.2 批量操作(Bulk Operations)

1 void putAll(Map<? extends K, ? extends V> m);//Copies all of the mappings from the specified map to this map(optional operation).
2 void clear();//Removes all of the mappings from this map (optional operation).

2.3 視圖操作(Views)

不知道這個翻譯是否恰當。

1 Set<K> keySet();//Returns a {Set} view of the keys contained in this map.
2 Collection<V> values();//Returns a {Collection} view of the values contained in this map.
3 Set<Map.Entry<K, V>> entrySet();//Returns a {Set} view of the mappings contained in this map.

2.4 內部接口Entry(interface Entry<K,V> {})

該接口內包含多個get、set、comparator方法。

interface Entry<K,V> {
        /**
         * Returns the key corresponding to this entry.
         *
         * @return the key corresponding to this entry
         * @throws IllegalStateException implementations may, but are not
         *         required to, throw this exception if the entry has been
         *         removed from the backing map.
         */
        K getKey();

        /**
         * Returns the value corresponding to this entry.  If the mapping
         * has been removed from the backing map (by the iterator's
         * <tt>remove</tt> operation), the results of this call are undefined.
         *
         * @return the value corresponding to this entry
         * @throws IllegalStateException implementations may, but are not
         *         required to, throw this exception if the entry has been
         *         removed from the backing map.
         */
        V getValue();

        /**
         * Replaces the value corresponding to this entry with the specified
         * value (optional operation).  (Writes through to the map.)  The
         * behavior of this call is undefined if the mapping has already been
         * removed from the map (by the iterator's <tt>remove</tt> operation).
         *
         * @param value new value to be stored in this entry
         * @return old value corresponding to the entry
         * @throws UnsupportedOperationException if the <tt>put</tt> operation
         *         is not supported by the backing map
         * @throws ClassCastException if the class of the specified value
         *         prevents it from being stored in the backing map
         * @throws NullPointerException if the backing map does not permit
         *         null values, and the specified value is null
         * @throws IllegalArgumentException if some property of this value
         *         prevents it from being stored in the backing map
         * @throws IllegalStateException implementations may, but are not
         *         required to, throw this exception if the entry has been
         *         removed from the backing map.
         */
        V setValue(V value);

        /**
         * Compares the specified object with this entry for equality.
         * Returns <tt>true</tt> if the given object is also a map entry and
         * the two entries represent the same mapping.  More formally, two
         * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
         * if<pre>
         *     (e1.getKey()==null ?
         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &amp;&amp;
         *     (e1.getValue()==null ?
         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
         * </pre>
         * This ensures that the <tt>equals</tt> method works properly across
         * different implementations of the <tt>Map.Entry</tt> interface.
         *
         * @param o object to be compared for equality with this map entry
         * @return <tt>true</tt> if the specified object is equal to this map
         *         entry
         */
        boolean equals(Object o);

        /**
         * Returns the hash code value for this map entry.  The hash code
         * of a map entry <tt>e</tt> is defined to be: <pre>
         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
         * </pre>
         * This ensures that <tt>e1.equals(e2)</tt> implies that
         * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
         * <tt>e1</tt> and <tt>e2</tt>, as required by the general
         * contract of <tt>Object.hashCode</tt>.
         *
         * @return the hash code value for this map entry
         * @see Object#hashCode()
         * @see Object#equals(Object)
         * @see #equals(Object)
         */
        int hashCode();

        /**
         * Returns a comparator that compares {@link Map.Entry} in natural order on key.
         *
         * <p>The returned comparator is serializable and throws {@link
         * NullPointerException} when comparing an entry with a null key.
         *
         * @param  <K> the {@link Comparable} type of then map keys
         * @param  <V> the type of the map values
         * @return a comparator that compares {@link Map.Entry} in natural order on key.
         * @see Comparable
         * @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());
        }

        /**
         * Returns a comparator that compares {@link Map.Entry} in natural order on value.
         *
         * <p>The returned comparator is serializable and throws {@link
         * NullPointerException} when comparing an entry with null values.
         *
         * @param <K> the type of the map keys
         * @param <V> the {@link Comparable} type of the map values
         * @return a comparator that compares {@link Map.Entry} in natural order on value.
         * @see Comparable
         * @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());
        }

        /**
         * Returns a comparator that compares {@link Map.Entry} by key using the given
         * {@link Comparator}.
         *
         * <p>The returned comparator is serializable if the specified comparator
         * is also serializable.
         *
         * @param  <K> the type of the map keys
         * @param  <V> the type of the map values
         * @param  cmp the key {@link Comparator}
         * @return a comparator that compares {@link Map.Entry} by the 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());
        }

        /**
         * Returns a comparator that compares {@link Map.Entry} by value using the given
         * {@link Comparator}.
         *
         * <p>The returned comparator is serializable if the specified comparator
         * is also serializable.
         *
         * @param  <K> the type of the map keys
         * @param  <V> the type of the map values
         * @param  cmp the value {@link Comparator}
         * @return a comparator that compares {@link Map.Entry} by the 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());
        }
    }
View Code

2.5 比較和獲取hash值(Comparison and hashing)

 1 /**
 2      * Compares the specified object with this map for equality.  Returns
 3      * <tt>true</tt> if the given object is also a map and the two maps
 4      * represent the same mappings.  More formally, two maps <tt>m1</tt> and
 5      * <tt>m2</tt> represent the same mappings if
 6      * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
 7      * <tt>equals</tt> method works properly across different implementations
 8      * of the <tt>Map</tt> interface.
 9      *
10      * @param o object to be compared for equality with this map
11      * @return <tt>true</tt> if the specified object is equal to this map
12      */
13     boolean equals(Object o);
14 
15     /**
16      * Returns the hash code value for this map.  The hash code of a map is
17      * defined to be the sum of the hash codes of each entry in the map's
18      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
19      * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
20      * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
21      * {@link Object#hashCode}.
22      *
23      * @return the hash code value for this map
24      * @see Map.Entry#hashCode()
25      * @see Object#equals(Object)
26      * @see #equals(Object)
27      */
28     int hashCode();
View Code

2.6 默認方法(Defaultable methods)

其中的方法在學習過程中很少很少的用到。

  1 /**
  2      * Returns the value to which the specified key is mapped, or
  3      * {@code defaultValue} if this map contains no mapping for the key.
  4      *
  5      * @implSpec
  6      * The default implementation makes no guarantees about synchronization
  7      * or atomicity properties of this method. Any implementation providing
  8      * atomicity guarantees must override this method and document its
  9      * concurrency properties.
 10      *
 11      * @param key the key whose associated value is to be returned
 12      * @param defaultValue the default mapping of the key
 13      * @return the value to which the specified key is mapped, or
 14      * {@code defaultValue} if this map contains no mapping for the key
 15      * @throws ClassCastException if the key is of an inappropriate type for
 16      * this map
 17      * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
 18      * @throws NullPointerException if the specified key is null and this map
 19      * does not permit null keys
 20      * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
 21      * @since 1.8
 22      */
 23     default V getOrDefault(Object key, V defaultValue) {
 24         V v;
 25         return (((v = get(key)) != null) || containsKey(key))
 26             ? v
 27             : defaultValue;
 28     }
 29 
 30     /**
 31      * Performs the given action for each entry in this map until all entries
 32      * have been processed or the action throws an exception.   Unless
 33      * otherwise specified by the implementing class, actions are performed in
 34      * the order of entry set iteration (if an iteration order is specified.)
 35      * Exceptions thrown by the action are relayed to the caller.
 36      *
 37      * @implSpec
 38      * The default implementation is equivalent to, for this {@code map}:
 39      * <pre> {@code
 40      * for (Map.Entry<K, V> entry : map.entrySet())
 41      *     action.accept(entry.getKey(), entry.getValue());
 42      * }</pre>
 43      *
 44      * The default implementation makes no guarantees about synchronization
 45      * or atomicity properties of this method. Any implementation providing
 46      * atomicity guarantees must override this method and document its
 47      * concurrency properties.
 48      *
 49      * @param action The action to be performed for each entry
 50      * @throws NullPointerException if the specified action is null
 51      * @throws ConcurrentModificationException if an entry is found to be
 52      * removed during iteration
 53      * @since 1.8
 54      */
 55     default void forEach(BiConsumer<? super K, ? super V> action) {
 56         Objects.requireNonNull(action);
 57         for (Map.Entry<K, V> entry : entrySet()) {
 58             K k;
 59             V v;
 60             try {
 61                 k = entry.getKey();
 62                 v = entry.getValue();
 63             } catch(IllegalStateException ise) {
 64                 // this usually means the entry is no longer in the map.
 65                 throw new ConcurrentModificationException(ise);
 66             }
 67             action.accept(k, v);
 68         }
 69     }
 70 
 71     /**
 72      * Replaces each entry's value with the result of invoking the given
 73      * function on that entry until all entries have been processed or the
 74      * function throws an exception.  Exceptions thrown by the function are
 75      * relayed to the caller.
 76      *
 77      * @implSpec
 78      * <p>The default implementation is equivalent to, for this {@code map}:
 79      * <pre> {@code
 80      * for (Map.Entry<K, V> entry : map.entrySet())
 81      *     entry.setValue(function.apply(entry.getKey(), entry.getValue()));
 82      * }</pre>
 83      *
 84      * <p>The default implementation makes no guarantees about synchronization
 85      * or atomicity properties of this method. Any implementation providing
 86      * atomicity guarantees must override this method and document its
 87      * concurrency properties.
 88      *
 89      * @param function the function to apply to each entry
 90      * @throws UnsupportedOperationException if the {@code set} operation
 91      * is not supported by this map's entry set iterator.
 92      * @throws ClassCastException if the class of a replacement value
 93      * prevents it from being stored in this map
 94      * @throws NullPointerException if the specified function is null, or the
 95      * specified replacement value is null, and this map does not permit null
 96      * values
 97      * @throws ClassCastException if a replacement value is of an inappropriate
 98      *         type for this map
 99      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
100      * @throws NullPointerException if function or a replacement value is null,
101      *         and this map does not permit null keys or values
102      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
103      * @throws IllegalArgumentException if some property of a replacement value
104      *         prevents it from being stored in this map
105      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
106      * @throws ConcurrentModificationException if an entry is found to be
107      * removed during iteration
108      * @since 1.8
109      */
110     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
111         Objects.requireNonNull(function);
112         for (Map.Entry<K, V> entry : entrySet()) {
113             K k;
114             V v;
115             try {
116                 k = entry.getKey();
117                 v = entry.getValue();
118             } catch(IllegalStateException ise) {
119                 // this usually means the entry is no longer in the map.
120                 throw new ConcurrentModificationException(ise);
121             }
122 
123             // ise thrown from function is not a cme.
124             v = function.apply(k, v);
125 
126             try {
127                 entry.setValue(v);
128             } catch(IllegalStateException ise) {
129                 // this usually means the entry is no longer in the map.
130                 throw new ConcurrentModificationException(ise);
131             }
132         }
133     }
134 
135     /**
136      * If the specified key is not already associated with a value (or is mapped
137      * to {@code null}) associates it with the given value and returns
138      * {@code null}, else returns the current value.
139      *
140      * @implSpec
141      * The default implementation is equivalent to, for this {@code
142      * map}:
143      *
144      * <pre> {@code
145      * V v = map.get(key);
146      * if (v == null)
147      *     v = map.put(key, value);
148      *
149      * return v;
150      * }</pre>
151      *
152      * <p>The default implementation makes no guarantees about synchronization
153      * or atomicity properties of this method. Any implementation providing
154      * atomicity guarantees must override this method and document its
155      * concurrency properties.
156      *
157      * @param key key with which the specified value is to be associated
158      * @param value value to be associated with the specified key
159      * @return the previous value associated with the specified key, or
160      *         {@code null} if there was no mapping for the key.
161      *         (A {@code null} return can also indicate that the map
162      *         previously associated {@code null} with the key,
163      *         if the implementation supports null values.)
164      * @throws UnsupportedOperationException if the {@code put} operation
165      *         is not supported by this map
166      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
167      * @throws ClassCastException if the key or value is of an inappropriate
168      *         type for this map
169      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
170      * @throws NullPointerException if the specified key or value is null,
171      *         and this map does not permit null keys or values
172      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
173      * @throws IllegalArgumentException if some property of the specified key
174      *         or value prevents it from being stored in this map
175      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
176      * @since 1.8
177      */
178     default V putIfAbsent(K key, V value) {
179         V v = get(key);
180         if (v == null) {
181             v = put(key, value);
182         }
183 
184         return v;
185     }
186 
187     /**
188      * Removes the entry for the specified key only if it is currently
189      * mapped to the specified value.
190      *
191      * @implSpec
192      * The default implementation is equivalent to, for this {@code map}:
193      *
194      * <pre> {@code
195      * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
196      *     map.remove(key);
197      *     return true;
198      * } else
199      *     return false;
200      * }</pre>
201      *
202      * <p>The default implementation makes no guarantees about synchronization
203      * or atomicity properties of this method. Any implementation providing
204      * atomicity guarantees must override this method and document its
205      * concurrency properties.
206      *
207      * @param key key with which the specified value is associated
208      * @param value value expected to be associated with the specified key
209      * @return {@code true} if the value was removed
210      * @throws UnsupportedOperationException if the {@code remove} operation
211      *         is not supported by this map
212      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
213      * @throws ClassCastException if the key or value is of an inappropriate
214      *         type for this map
215      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
216      * @throws NullPointerException if the specified key or value is null,
217      *         and this map does not permit null keys or values
218      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
219      * @since 1.8
220      */
221     default boolean remove(Object key, Object value) {
222         Object curValue = get(key);
223         if (!Objects.equals(curValue, value) ||
224             (curValue == null && !containsKey(key))) {
225             return false;
226         }
227         remove(key);
228         return true;
229     }
230 
231     /**
232      * Replaces the entry for the specified key only if currently
233      * mapped to the specified value.
234      *
235      * @implSpec
236      * The default implementation is equivalent to, for this {@code map}:
237      *
238      * <pre> {@code
239      * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
240      *     map.put(key, newValue);
241      *     return true;
242      * } else
243      *     return false;
244      * }</pre>
245      *
246      * The default implementation does not throw NullPointerException
247      * for maps that do not support null values if oldValue is null unless
248      * newValue is also null.
249      *
250      * <p>The default implementation makes no guarantees about synchronization
251      * or atomicity properties of this method. Any implementation providing
252      * atomicity guarantees must override this method and document its
253      * concurrency properties.
254      *
255      * @param key key with which the specified value is associated
256      * @param oldValue value expected to be associated with the specified key
257      * @param newValue value to be associated with the specified key
258      * @return {@code true} if the value was replaced
259      * @throws UnsupportedOperationException if the {@code put} operation
260      *         is not supported by this map
261      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
262      * @throws ClassCastException if the class of a specified key or value
263      *         prevents it from being stored in this map
264      * @throws NullPointerException if a specified key or newValue is null,
265      *         and this map does not permit null keys or values
266      * @throws NullPointerException if oldValue is null and this map does not
267      *         permit null values
268      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
269      * @throws IllegalArgumentException if some property of a specified key
270      *         or value prevents it from being stored in this map
271      * @since 1.8
272      */
273     default boolean replace(K key, V oldValue, V newValue) {
274         Object curValue = get(key);
275         if (!Objects.equals(curValue, oldValue) ||
276             (curValue == null && !containsKey(key))) {
277             return false;
278         }
279         put(key, newValue);
280         return true;
281     }
282 
283     /**
284      * Replaces the entry for the specified key only if it is
285      * currently mapped to some value.
286      *
287      * @implSpec
288      * The default implementation is equivalent to, for this {@code map}:
289      *
290      * <pre> {@code
291      * if (map.containsKey(key)) {
292      *     return map.put(key, value);
293      * } else
294      *     return null;
295      * }</pre>
296      *
297      * <p>The default implementation makes no guarantees about synchronization
298      * or atomicity properties of this method. Any implementation providing
299      * atomicity guarantees must override this method and document its
300      * concurrency properties.
301       *
302      * @param key key with which the specified value is associated
303      * @param value value to be associated with the specified key
304      * @return the previous value associated with the specified key, or
305      *         {@code null} if there was no mapping for the key.
306      *         (A {@code null} return can also indicate that the map
307      *         previously associated {@code null} with the key,
308      *         if the implementation supports null values.)
309      * @throws UnsupportedOperationException if the {@code put} operation
310      *         is not supported by this map
311      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
312      * @throws ClassCastException if the class of the specified key or value
313      *         prevents it from being stored in this map
314      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
315      * @throws NullPointerException if the specified key or value is null,
316      *         and this map does not permit null keys or values
317      * @throws IllegalArgumentException if some property of the specified key
318      *         or value prevents it from being stored in this map
319      * @since 1.8
320      */
321     default V replace(K key, V value) {
322         V curValue;
323         if (((curValue = get(key)) != null) || containsKey(key)) {
324             curValue = put(key, value);
325         }
326         return curValue;
327     }
328 
329     /**
330      * If the specified key is not already associated with a value (or is mapped
331      * to {@code null}), attempts to compute its value using the given mapping
332      * function and enters it into this map unless {@code null}.
333      *
334      * <p>If the function returns {@code null} no mapping is recorded. If
335      * the function itself throws an (unchecked) exception, the
336      * exception is rethrown, and no mapping is recorded.  The most
337      * common usage is to construct a new object serving as an initial
338      * mapped value or memoized result, as in:
339      *
340      * <pre> {@code
341      * map.computeIfAbsent(key, k -> new Value(f(k)));
342      * }</pre>
343      *
344      * <p>Or to implement a multi-value map, {@code Map<K,Collection<V>>},
345      * supporting multiple values per key:
346      *
347      * <pre> {@code
348      * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
349      * }</pre>
350      *
351      *
352      * @implSpec
353      * The default implementation is equivalent to the following steps for this
354      * {@code map}, then returning the current value or {@code null} if now
355      * absent:
356      *
357      * <pre> {@code
358      * if (map.get(key) == null) {
359      *     V newValue = mappingFunction.apply(key);
360      *     if (newValue != null)
361      *         map.put(key, newValue);
362      * }
363      * }</pre>
364      *
365      * <p>The default implementation makes no guarantees about synchronization
366      * or atomicity properties of this method. Any implementation providing
367      * atomicity guarantees must override this method and document its
368      * concurrency properties. In particular, all implementations of
369      * subinterface {@link java.util.concurrent.ConcurrentMap} must document
370      * whether the function is applied once atomically only if the value is not
371      * present.
372      *
373      * @param key key with which the specified value is to be associated
374      * @param mappingFunction the function to compute a value
375      * @return the current (existing or computed) value associated with
376      *         the specified key, or null if the computed value is null
377      * @throws NullPointerException if the specified key is null and
378      *         this map does not support null keys, or the mappingFunction
379      *         is null
380      * @throws UnsupportedOperationException if the {@code put} operation
381      *         is not supported by this map
382      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
383      * @throws ClassCastException if the class of the specified key or value
384      *         prevents it from being stored in this map
385      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
386      * @since 1.8
387      */
388     default V computeIfAbsent(K key,
389             Function<? super K, ? extends V> mappingFunction) {
390         Objects.requireNonNull(mappingFunction);
391         V v;
392         if ((v = get(key)) == null) {
393             V newValue;
394             if ((newValue = mappingFunction.apply(key)) != null) {
395                 put(key, newValue);
396                 return newValue;
397             }
398         }
399 
400         return v;
401     }
402 
403     /**
404      * If the value for the specified key is present and non-null, attempts to
405      * compute a new mapping given the key and its current mapped value.
406      *
407      * <p>If the function returns {@code null}, the mapping is removed.  If the
408      * function itself throws an (unchecked) exception, the exception is
409      * rethrown, and the current mapping is left unchanged.
410     *
411      * @implSpec
412      * The default implementation is equivalent to performing the following
413      * steps for this {@code map}, then returning the current value or
414      * {@code null} if now absent:
415      *
416      * <pre> {@code
417      * if (map.get(key) != null) {
418      *     V oldValue = map.get(key);
419      *     V newValue = remappingFunction.apply(key, oldValue);
420      *     if (newValue != null)
421      *         map.put(key, newValue);
422      *     else
423      *         map.remove(key);
424      * }
425      * }</pre>
426      *
427      * <p>The default implementation makes no guarantees about synchronization
428      * or atomicity properties of this method. Any implementation providing
429      * atomicity guarantees must override this method and document its
430      * concurrency properties. In particular, all implementations of
431      * subinterface {@link java.util.concurrent.ConcurrentMap} must document
432      * whether the function is applied once atomically only if the value is not
433      * present.
434      *
435      * @param key key with which the specified value is to be associated
436      * @param remappingFunction the function to compute a value
437      * @return the new value associated with the specified key, or null if none
438      * @throws NullPointerException if the specified key is null and
439      *         this map does not support null keys, or the
440      *         remappingFunction is null
441      * @throws UnsupportedOperationException if the {@code put} operation
442      *         is not supported by this map
443      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
444      * @throws ClassCastException if the class of the specified key or value
445      *         prevents it from being stored in this map
446      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
447      * @since 1.8
448      */
449     default V computeIfPresent(K key,
450             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
451         Objects.requireNonNull(remappingFunction);
452         V oldValue;
453         if ((oldValue = get(key)) != null) {
454             V newValue = remappingFunction.apply(key, oldValue);
455             if (newValue != null) {
456                 put(key, newValue);
457                 return newValue;
458             } else {
459                 remove(key);
460                 return null;
461             }
462         } else {
463             return null;
464         }
465     }
466 
467     /**
468      * Attempts to compute a mapping for the specified key and its current
469      * mapped value (or {@code null} if there is no current mapping). For
470      * example, to either create or append a {@code String} msg to a value
471      * mapping:
472      *
473      * <pre> {@code
474      * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
475      * (Method {@link #merge merge()} is often simpler to use for such purposes.)
476      *
477      * <p>If the function returns {@code null}, the mapping is removed (or
478      * remains absent if initially absent).  If the function itself throws an
479      * (unchecked) exception, the exception is rethrown, and the current mapping
480      * is left unchanged.
481      *
482      * @implSpec
483      * The default implementation is equivalent to performing the following
484      * steps for this {@code map}, then returning the current value or
485      * {@code null} if absent:
486      *
487      * <pre> {@code
488      * V oldValue = map.get(key);
489      * V newValue = remappingFunction.apply(key, oldValue);
490      * if (oldValue != null ) {
491      *    if (newValue != null)
492      *       map.put(key, newValue);
493      *    else
494      *       map.remove(key);
495      * } else {
496      *    if (newValue != null)
497      *       map.put(key, newValue);
498      *    else
499      *       return null;
500      * }
501      * }</pre>
502      *
503      * <p>The default implementation makes no guarantees about synchronization
504      * or atomicity properties of this method. Any implementation providing
505      * atomicity guarantees must override this method and document its
506      * concurrency properties. In particular, all implementations of
507      * subinterface {@link java.util.concurrent.ConcurrentMap} must document
508      * whether the function is applied once atomically only if the value is not
509      * present.
510      *
511      * @param key key with which the specified value is to be associated
512      * @param remappingFunction the function to compute a value
513      * @return the new value associated with the specified key, or null if none
514      * @throws NullPointerException if the specified key is null and
515      *         this map does not support null keys, or the
516      *         remappingFunction is null
517      * @throws UnsupportedOperationException if the {@code put} operation
518      *         is not supported by this map
519      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
520      * @throws ClassCastException if the class of the specified key or value
521      *         prevents it from being stored in this map
522      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
523      * @since 1.8
524      */
525     default V compute(K key,
526             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
527         Objects.requireNonNull(remappingFunction);
528         V oldValue = get(key);
529 
530         V newValue = remappingFunction.apply(key, oldValue);
531         if (newValue == null) {
532             // delete mapping
533             if (oldValue != null || containsKey(key)) {
534                 // something to remove
535                 remove(key);
536                 return null;
537             } else {
538                 // nothing to do. Leave things as they were.
539                 return null;
540             }
541         } else {
542             // add or replace old mapping
543             put(key, newValue);
544             return newValue;
545         }
546     }
547 
548     /**
549      * If the specified key is not already associated with a value or is
550      * associated with null, associates it with the given non-null value.
551      * Otherwise, replaces the associated value with the results of the given
552      * remapping function, or removes if the result is {@code null}. This
553      * method may be of use when combining multiple mapped values for a key.
554      * For example, to either create or append a {@code String msg} to a
555      * value mapping:
556      *
557      * <pre> {@code
558      * map.merge(key, msg, String::concat)
559      * }</pre>
560      *
561      * <p>If the function returns {@code null} the mapping is removed.  If the
562      * function itself throws an (unchecked) exception, the exception is
563      * rethrown, and the current mapping is left unchanged.
564      *
565      * @implSpec
566      * The default implementation is equivalent to performing the following
567      * steps for this {@code map}, then returning the current value or
568      * {@code null} if absent:
569      *
570      * <pre> {@code
571      * V oldValue = map.get(key);
572      * V newValue = (oldValue == null) ? value :
573      *              remappingFunction.apply(oldValue, value);
574      * if (newValue == null)
575      *     map.remove(key);
576      * else
577      *     map.put(key, newValue);
578      * }</pre>
579      *
580      * <p>The default implementation makes no guarantees about synchronization
581      * or atomicity properties of this method. Any implementation providing
582      * atomicity guarantees must override this method and document its
583      * concurrency properties. In particular, all implementations of
584      * subinterface {@link java.util.concurrent.ConcurrentMap} must document
585      * whether the function is applied once atomically only if the value is not
586      * present.
587      *
588      * @param key key with which the resulting value is to be associated
589      * @param value the non-null value to be merged with the existing value
590      *        associated with the key or, if no existing value or a null value
591      *        is associated with the key, to be associated with the key
592      * @param remappingFunction the function to recompute a value if present
593      * @return the new value associated with the specified key, or null if no
594      *         value is associated with the key
595      * @throws UnsupportedOperationException if the {@code put} operation
596      *         is not supported by this map
597      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
598      * @throws ClassCastException if the class of the specified key or value
599      *         prevents it from being stored in this map
600      *         (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
601      * @throws NullPointerException if the specified key is null and this map
602      *         does not support null keys or the value or remappingFunction is
603      *         null
604      * @since 1.8
605      */
606     default V merge(K key, V value,
607             BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
608         Objects.requireNonNull(remappingFunction);
609         Objects.requireNonNull(value);
610         V oldValue = get(key);
611         V newValue = (oldValue == null) ? value :
612                    remappingFunction.apply(oldValue, value);
613         if(newValue == null) {
614             remove(key);
615         } else {
616             put(key, newValue);
617         }
618         return newValue;
619     }
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM