1 /*
2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util;
27
28 import java.util.function.Consumer;
29 import java.util.function.BiConsumer;
30 import java.util.function.BiFunction;
31 import java.io.IOException;
32
33 /**
34 * <p>Hash table and linked list implementation of the {@code Map} interface,
35 * with predictable iteration order. This implementation differs from
36 * {@code HashMap} in that it maintains a doubly-linked list running through
37 * all of its entries. This linked list defines the iteration ordering,
38 * which is normally the order in which keys were inserted into the map
39 * (<i>insertion-order</i>). Note that insertion order is not affected
40 * if a key is <i>re-inserted</i> into the map. (A key {@code k} is
41 * reinserted into a map {@code m} if {@code m.put(k, v)} is invoked when
42 * {@code m.containsKey(k)} would return {@code true} immediately prior to
43 * the invocation.)
44 *
45 * <p>This implementation spares its clients from the unspecified, generally
46 * chaotic ordering provided by {@link HashMap} (and {@link Hashtable}),
47 * without incurring the increased cost associated with {@link TreeMap}. It
48 * can be used to produce a copy of a map that has the same order as the
49 * original, regardless of the original map's implementation:
50 * <pre>
51 * void foo(Map m) {
52 * Map copy = new LinkedHashMap(m);
53 * ...
54 * }
55 * </pre>
56 * This technique is particularly useful if a module takes a map on input,
57 * copies it, and later returns results whose order is determined by that of
58 * the copy. (Clients generally appreciate having things returned in the same
59 * order they were presented.)
60 *
61 * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
62 * provided to create a linked hash map whose order of iteration is the order
63 * in which its entries were last accessed, from least-recently accessed to
64 * most-recently (<i>access-order</i>). This kind of map is well-suited to
65 * building LRU caches. Invoking the {@code put}, {@code putIfAbsent},
66 * {@code get}, {@code getOrDefault}, {@code compute}, {@code computeIfAbsent},
67 * {@code computeIfPresent}, or {@code merge} methods results
68 * in an access to the corresponding entry (assuming it exists after the
69 * invocation completes). The {@code replace} methods only result in an access
70 * of the entry if the value is replaced. The {@code putAll} method generates one
71 * entry access for each mapping in the specified map, in the order that
72 * key-value mappings are provided by the specified map's entry set iterator.
73 * <i>No other methods generate entry accesses.</i> In particular, operations
74 * on collection-views do <i>not</i> affect the order of iteration of the
75 * backing map.
76 *
77 * <p>The {@link #removeEldestEntry(Map.Entry)} method may be overridden to
78 * impose a policy for removing stale mappings automatically when new mappings
79 * are added to the map.
80 *
81 * <p>This class provides all of the optional {@code Map} operations, and
82 * permits null elements. Like {@code HashMap}, it provides constant-time
83 * performance for the basic operations ({@code add}, {@code contains} and
84 * {@code remove}), assuming the hash function disperses elements
85 * properly among the buckets. Performance is likely to be just slightly
86 * below that of {@code HashMap}, due to the added expense of maintaining the
87 * linked list, with one exception: Iteration over the collection-views
88 * of a {@code LinkedHashMap} requires time proportional to the <i>size</i>
89 * of the map, regardless of its capacity. Iteration over a {@code HashMap}
90 * is likely to be more expensive, requiring time proportional to its
91 * <i>capacity</i>.
92 *
93 * <p>A linked hash map has two parameters that affect its performance:
94 * <i>initial capacity</i> and <i>load factor</i>. They are defined precisely
95 * as for {@code HashMap}. Note, however, that the penalty for choosing an
96 * excessively high value for initial capacity is less severe for this class
97 * than for {@code HashMap}, as iteration times for this class are unaffected
98 * by capacity.
99 *
100 * <p><strong>Note that this implementation is not synchronized.</strong>
101 * If multiple threads access a linked hash map concurrently, and at least
102 * one of the threads modifies the map structurally, it <em>must</em> be
103 * synchronized externally. This is typically accomplished by
104 * synchronizing on some object that naturally encapsulates the map.
105 *
106 * If no such object exists, the map should be "wrapped" using the
107 * {@link Collections#synchronizedMap Collections.synchronizedMap}
108 * method. This is best done at creation time, to prevent accidental
109 * unsynchronized access to the map:<pre>
110 * Map m = Collections.synchronizedMap(new LinkedHashMap(...));</pre>
111 *
112 * A structural modification is any operation that adds or deletes one or more
113 * mappings or, in the case of access-ordered linked hash maps, affects
114 * iteration order. In insertion-ordered linked hash maps, merely changing
115 * the value associated with a key that is already contained in the map is not
116 * a structural modification. <strong>In access-ordered linked hash maps,
117 * merely querying the map with {@code get} is a structural modification.
118 * </strong>)
119 *
120 * <p>The iterators returned by the {@code iterator} method of the collections
121 * returned by all of this class's collection view methods are
122 * <em>fail-fast</em>: if the map is structurally modified at any time after
123 * the iterator is created, in any way except through the iterator's own
124 * {@code remove} method, the iterator will throw a {@link
125 * ConcurrentModificationException}. Thus, in the face of concurrent
126 * modification, the iterator fails quickly and cleanly, rather than risking
127 * arbitrary, non-deterministic behavior at an undetermined time in the future.
128 *
129 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
130 * as it is, generally speaking, impossible to make any hard guarantees in the
131 * presence of unsynchronized concurrent modification. Fail-fast iterators
132 * throw {@code ConcurrentModificationException} on a best-effort basis.
133 * Therefore, it would be wrong to write a program that depended on this
134 * exception for its correctness: <i>the fail-fast behavior of iterators
135 * should be used only to detect bugs.</i>
136 *
137 * <p>The spliterators returned by the spliterator method of the collections
138 * returned by all of this class's collection view methods are
139 * <em><a href="Spliterator.html#binding">late-binding</a></em>,
140 * <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
141 *
142 * <p>This class is a member of the
143 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
144 * Java Collections Framework</a>.
145 *
146 * @implNote
147 * The spliterators returned by the spliterator method of the collections
148 * returned by all of this class's collection view methods are created from
149 * the iterators of the corresponding collections.
150 *
151 * @param <K> the type of keys maintained by this map
152 * @param <V> the type of mapped values
153 *
154 * @author Josh Bloch
155 * @see Object#hashCode()
156 * @see Collection
157 * @see Map
158 * @see HashMap
159 * @see TreeMap
160 * @see Hashtable
161 * @since 1.4
162 */
163 public class LinkedHashMap<K,V>
164 extends HashMap<K,V>
165 implements Map<K,V>
166 {
167
168 /*
169 * Implementation note. A previous version of this class was
170 * internally structured a little differently. Because superclass
171 * HashMap now uses trees for some of its nodes, class
172 * LinkedHashMap.Entry is now treated as intermediary node class
173 * that can also be converted to tree form. The name of this
174 * class, LinkedHashMap.Entry, is confusing in several ways in its
175 * current context, but cannot be changed. Otherwise, even though
176 * it is not exported outside this package, some existing source
177 * code is known to have relied on a symbol resolution corner case
178 * rule in calls to removeEldestEntry that suppressed compilation
179 * errors due to ambiguous usages. So, we keep the name to
180 * preserve unmodified compilability.
181 *
182 * The changes in node classes also require using two fields
183 * (head, tail) rather than a pointer to a header node to maintain
184 * the doubly-linked before/after list. This class also
185 * previously used a different style of callback methods upon
186 * access, insertion, and removal.
187 */
188
189 /**
190 * HashMap.Node subclass for normal LinkedHashMap entries.
191 */
192 static class Entry<K,V> extends HashMap.Node<K,V> {
193 Entry<K,V> before, after;
194 Entry(int hash, K key, V value, Node<K,V> next) {
195 super(hash, key, value, next);
196 }
197 }
198
199 private static final long serialVersionUID = 3801124242820219131L;
200
201 /**
202 * The head (eldest) of the doubly linked list.
203 */
204 transient LinkedHashMap.Entry<K,V> head;
205
206 /**
207 * The tail (youngest) of the doubly linked list.
208 */
209 transient LinkedHashMap.Entry<K,V> tail;
210
211 /**
212 * The iteration ordering method for this linked hash map: {@code true}
213 * for access-order, {@code false} for insertion-order.
214 *
215 * @serial
216 */
217 final boolean accessOrder;
218
219 // internal utilities
220
221 // link at the end of list
222 private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
223 LinkedHashMap.Entry<K,V> last = tail;
224 tail = p;
225 if (last == null)
226 head = p;
227 else {
228 p.before = last;
229 last.after = p;
230 }
231 }
232
233 // apply src's links to dst
234 private void transferLinks(LinkedHashMap.Entry<K,V> src,
235 LinkedHashMap.Entry<K,V> dst) {
236 LinkedHashMap.Entry<K,V> b = dst.before = src.before;
237 LinkedHashMap.Entry<K,V> a = dst.after = src.after;
238 if (b == null)
239 head = dst;
240 else
241 b.after = dst;
242 if (a == null)
243 tail = dst;
244 else
245 a.before = dst;
246 }
247
248 // overrides of HashMap hook methods
249
250 void reinitialize() {
251 super.reinitialize();
252 head = tail = null;
253 }
254
255 Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
256 LinkedHashMap.Entry<K,V> p =
257 new LinkedHashMap.Entry<>(hash, key, value, e);
258 linkNodeLast(p);
259 return p;
260 }
261
262 Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
263 LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
264 LinkedHashMap.Entry<K,V> t =
265 new LinkedHashMap.Entry<>(q.hash, q.key, q.value, next);
266 transferLinks(q, t);
267 return t;
268 }
269
270 TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
271 TreeNode<K,V> p = new TreeNode<>(hash, key, value, next);
272 linkNodeLast(p);
273 return p;
274 }
275
276 TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
277 LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
278 TreeNode<K,V> t = new TreeNode<>(q.hash, q.key, q.value, next);
279 transferLinks(q, t);
280 return t;
281 }
282
283 void afterNodeRemoval(Node<K,V> e) { // unlink
284 LinkedHashMap.Entry<K,V> p =
285 (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
286 p.before = p.after = null;
287 if (b == null)
288 head = a;
289 else
290 b.after = a;
291 if (a == null)
292 tail = b;
293 else
294 a.before = b;
295 }
296
297 void afterNodeInsertion(boolean evict) { // possibly remove eldest
298 LinkedHashMap.Entry<K,V> first;
299 if (evict && (first = head) != null && removeEldestEntry(first)) {
300 K key = first.key;
301 removeNode(hash(key), key, null, false, true);
302 }
303 }
304
305 void afterNodeAccess(Node<K,V> e) { // move node to last
306 LinkedHashMap.Entry<K,V> last;
307 if (accessOrder && (last = tail) != e) {
308 LinkedHashMap.Entry<K,V> p =
309 (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
310 p.after = null;
311 if (b == null)
312 head = a;
313 else
314 b.after = a;
315 if (a != null)
316 a.before = b;
317 else
318 last = b;
319 if (last == null)
320 head = p;
321 else {
322 p.before = last;
323 last.after = p;
324 }
325 tail = p;
326 ++modCount;
327 }
328 }
329
330 void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
331 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
332 s.writeObject(e.key);
333 s.writeObject(e.value);
334 }
335 }
336
337 /**
338 * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
339 * with the specified initial capacity and load factor.
340 *
341 * @param initialCapacity the initial capacity
342 * @param loadFactor the load factor
343 * @throws IllegalArgumentException if the initial capacity is negative
344 * or the load factor is nonpositive
345 */
346 public LinkedHashMap(int initialCapacity, float loadFactor) {
347 super(initialCapacity, loadFactor);
348 accessOrder = false;
349 }
350
351 /**
352 * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
353 * with the specified initial capacity and a default load factor (0.75).
354 *
355 * @param initialCapacity the initial capacity
356 * @throws IllegalArgumentException if the initial capacity is negative
357 */
358 public LinkedHashMap(int initialCapacity) {
359 super(initialCapacity);
360 accessOrder = false;
361 }
362
363 /**
364 * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
365 * with the default initial capacity (16) and load factor (0.75).
366 */
367 public LinkedHashMap() {
368 super();
369 accessOrder = false;
370 }
371
372 /**
373 * Constructs an insertion-ordered {@code LinkedHashMap} instance with
374 * the same mappings as the specified map. The {@code LinkedHashMap}
375 * instance is created with a default load factor (0.75) and an initial
376 * capacity sufficient to hold the mappings in the specified map.
377 *
378 * @param m the map whose mappings are to be placed in this map
379 * @throws NullPointerException if the specified map is null
380 */
381 public LinkedHashMap(Map<? extends K, ? extends V> m) {
382 super();
383 accessOrder = false;
384 putMapEntries(m, false);
385 }
386
387 /**
388 * Constructs an empty {@code LinkedHashMap} instance with the
389 * specified initial capacity, load factor and ordering mode.
390 *
391 * @param initialCapacity the initial capacity
392 * @param loadFactor the load factor
393 * @param accessOrder the ordering mode - {@code true} for
394 * access-order, {@code false} for insertion-order
395 * @throws IllegalArgumentException if the initial capacity is negative
396 * or the load factor is nonpositive
397 */
398 public LinkedHashMap(int initialCapacity,
399 float loadFactor,
400 boolean accessOrder) {
401 super(initialCapacity, loadFactor);
402 this.accessOrder = accessOrder;
403 }
404
405
406 /**
407 * Returns {@code true} if this map maps one or more keys to the
408 * specified value.
409 *
410 * @param value value whose presence in this map is to be tested
411 * @return {@code true} if this map maps one or more keys to the
412 * specified value
413 */
414 public boolean containsValue(Object value) {
415 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
416 V v = e.value;
417 if (v == value || (value != null && value.equals(v)))
418 return true;
419 }
420 return false;
421 }
422
423 /**
424 * Returns the value to which the specified key is mapped,
425 * or {@code null} if this map contains no mapping for the key.
426 *
427 * <p>More formally, if this map contains a mapping from a key
428 * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
429 * key.equals(k))}, then this method returns {@code v}; otherwise
430 * it returns {@code null}. (There can be at most one such mapping.)
431 *
432 * <p>A return value of {@code null} does not <i>necessarily</i>
433 * indicate that the map contains no mapping for the key; it's also
434 * possible that the map explicitly maps the key to {@code null}.
435 * The {@link #containsKey containsKey} operation may be used to
436 * distinguish these two cases.
437 */
438 public V get(Object key) {
439 Node<K,V> e;
440 if ((e = getNode(hash(key), key)) == null)
441 return null;
442 if (accessOrder)
443 afterNodeAccess(e);
444 return e.value;
445 }
446
447 /**
448 * {@inheritDoc}
449 */
450 public V getOrDefault(Object key, V defaultValue) {
451 Node<K,V> e;
452 if ((e = getNode(hash(key), key)) == null)
453 return defaultValue;
454 if (accessOrder)
455 afterNodeAccess(e);
456 return e.value;
457 }
458
459 /**
460 * {@inheritDoc}
461 */
462 public void clear() {
463 super.clear();
464 head = tail = null;
465 }
466
467 /**
468 * Returns {@code true} if this map should remove its eldest entry.
469 * This method is invoked by {@code put} and {@code putAll} after
470 * inserting a new entry into the map. It provides the implementor
471 * with the opportunity to remove the eldest entry each time a new one
472 * is added. This is useful if the map represents a cache: it allows
473 * the map to reduce memory consumption by deleting stale entries.
474 *
475 * <p>Sample use: this override will allow the map to grow up to 100
476 * entries and then delete the eldest entry each time a new entry is
477 * added, maintaining a steady state of 100 entries.
478 * <pre>
479 * private static final int MAX_ENTRIES = 100;
480 *
481 * protected boolean removeEldestEntry(Map.Entry eldest) {
482 * return size() > MAX_ENTRIES;
483 * }
484 * </pre>
485 *
486 * <p>This method typically does not modify the map in any way,
487 * instead allowing the map to modify itself as directed by its
488 * return value. It <i>is</i> permitted for this method to modify
489 * the map directly, but if it does so, it <i>must</i> return
490 * {@code false} (indicating that the map should not attempt any
491 * further modification). The effects of returning {@code true}
492 * after modifying the map from within this method are unspecified.
493 *
494 * <p>This implementation merely returns {@code false} (so that this
495 * map acts like a normal map - the eldest element is never removed).
496 *
497 * @param eldest The least recently inserted entry in the map, or if
498 * this is an access-ordered map, the least recently accessed
499 * entry. This is the entry that will be removed it this
500 * method returns {@code true}. If the map was empty prior
501 * to the {@code put} or {@code putAll} invocation resulting
502 * in this invocation, this will be the entry that was just
503 * inserted; in other words, if the map contains a single
504 * entry, the eldest entry is also the newest.
505 * @return {@code true} if the eldest entry should be removed
506 * from the map; {@code false} if it should be retained.
507 */
508 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
509 return false;
510 }
511
512 /**
513 * Returns a {@link Set} view of the keys contained in this map.
514 * The set is backed by the map, so changes to the map are
515 * reflected in the set, and vice-versa. If the map is modified
516 * while an iteration over the set is in progress (except through
517 * the iterator's own {@code remove} operation), the results of
518 * the iteration are undefined. The set supports element removal,
519 * which removes the corresponding mapping from the map, via the
520 * {@code Iterator.remove}, {@code Set.remove},
521 * {@code removeAll}, {@code retainAll}, and {@code clear}
522 * operations. It does not support the {@code add} or {@code addAll}
523 * operations.
524 * Its {@link Spliterator} typically provides faster sequential
525 * performance but much poorer parallel performance than that of
526 * {@code HashMap}.
527 *
528 * @return a set view of the keys contained in this map
529 */
530 public Set<K> keySet() {
531 Set<K> ks = keySet;
532 if (ks == null) {
533 ks = new LinkedKeySet();
534 keySet = ks;
535 }
536 return ks;
537 }
538
539 final class LinkedKeySet extends AbstractSet<K> {
540 public final int size() { return size; }
541 public final void clear() { LinkedHashMap.this.clear(); }
542 public final Iterator<K> iterator() {
543 return new LinkedKeyIterator();
544 }
545 public final boolean contains(Object o) { return containsKey(o); }
546 public final boolean remove(Object key) {
547 return removeNode(hash(key), key, null, false, true) != null;
548 }
549 public final Spliterator<K> spliterator() {
550 return Spliterators.spliterator(this, Spliterator.SIZED |
551 Spliterator.ORDERED |
552 Spliterator.DISTINCT);
553 }
554 public final void forEach(Consumer<? super K> action) {
555 if (action == null)
556 throw new NullPointerException();
557 int mc = modCount;
558 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
559 action.accept(e.key);
560 if (modCount != mc)
561 throw new ConcurrentModificationException();
562 }
563 }
564
565 /**
566 * Returns a {@link Collection} view of the values contained in this map.
567 * The collection is backed by the map, so changes to the map are
568 * reflected in the collection, and vice-versa. If the map is
569 * modified while an iteration over the collection is in progress
570 * (except through the iterator's own {@code remove} operation),
571 * the results of the iteration are undefined. The collection
572 * supports element removal, which removes the corresponding
573 * mapping from the map, via the {@code Iterator.remove},
574 * {@code Collection.remove}, {@code removeAll},
575 * {@code retainAll} and {@code clear} operations. It does not
576 * support the {@code add} or {@code addAll} operations.
577 * Its {@link Spliterator} typically provides faster sequential
578 * performance but much poorer parallel performance than that of
579 * {@code HashMap}.
580 *
581 * @return a view of the values contained in this map
582 */
583 public Collection<V> values() {
584 Collection<V> vs = values;
585 if (vs == null) {
586 vs = new LinkedValues();
587 values = vs;
588 }
589 return vs;
590 }
591
592 final class LinkedValues extends AbstractCollection<V> {
593 public final int size() { return size; }
594 public final void clear() { LinkedHashMap.this.clear(); }
595 public final Iterator<V> iterator() {
596 return new LinkedValueIterator();
597 }
598 public final boolean contains(Object o) { return containsValue(o); }
599 public final Spliterator<V> spliterator() {
600 return Spliterators.spliterator(this, Spliterator.SIZED |
601 Spliterator.ORDERED);
602 }
603 public final void forEach(Consumer<? super V> action) {
604 if (action == null)
605 throw new NullPointerException();
606 int mc = modCount;
607 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
608 action.accept(e.value);
609 if (modCount != mc)
610 throw new ConcurrentModificationException();
611 }
612 }
613
614 /**
615 * Returns a {@link Set} view of the mappings contained in this map.
616 * The set is backed by the map, so changes to the map are
617 * reflected in the set, and vice-versa. If the map is modified
618 * while an iteration over the set is in progress (except through
619 * the iterator's own {@code remove} operation, or through the
620 * {@code setValue} operation on a map entry returned by the
621 * iterator) the results of the iteration are undefined. The set
622 * supports element removal, which removes the corresponding
623 * mapping from the map, via the {@code Iterator.remove},
624 * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
625 * {@code clear} operations. It does not support the
626 * {@code add} or {@code addAll} operations.
627 * Its {@link Spliterator} typically provides faster sequential
628 * performance but much poorer parallel performance than that of
629 * {@code HashMap}.
630 *
631 * @return a set view of the mappings contained in this map
632 */
633 public Set<Map.Entry<K,V>> entrySet() {
634 Set<Map.Entry<K,V>> es;
635 return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
636 }
637
638 final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
639 public final int size() { return size; }
640 public final void clear() { LinkedHashMap.this.clear(); }
641 public final Iterator<Map.Entry<K,V>> iterator() {
642 return new LinkedEntryIterator();
643 }
644 public final boolean contains(Object o) {
645 if (!(o instanceof Map.Entry))
646 return false;
647 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
648 Object key = e.getKey();
649 Node<K,V> candidate = getNode(hash(key), key);
650 return candidate != null && candidate.equals(e);
651 }
652 public final boolean remove(Object o) {
653 if (o instanceof Map.Entry) {
654 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
655 Object key = e.getKey();
656 Object value = e.getValue();
657 return removeNode(hash(key), key, value, true, true) != null;
658 }
659 return false;
660 }
661 public final Spliterator<Map.Entry<K,V>> spliterator() {
662 return Spliterators.spliterator(this, Spliterator.SIZED |
663 Spliterator.ORDERED |
664 Spliterator.DISTINCT);
665 }
666 public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
667 if (action == null)
668 throw new NullPointerException();
669 int mc = modCount;
670 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
671 action.accept(e);
672 if (modCount != mc)
673 throw new ConcurrentModificationException();
674 }
675 }
676
677 // Map overrides
678
679 public void forEach(BiConsumer<? super K, ? super V> action) {
680 if (action == null)
681 throw new NullPointerException();
682 int mc = modCount;
683 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
684 action.accept(e.key, e.value);
685 if (modCount != mc)
686 throw new ConcurrentModificationException();
687 }
688
689 public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
690 if (function == null)
691 throw new NullPointerException();
692 int mc = modCount;
693 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
694 e.value = function.apply(e.key, e.value);
695 if (modCount != mc)
696 throw new ConcurrentModificationException();
697 }
698
699 // Iterators
700
701 abstract class LinkedHashIterator {
702 LinkedHashMap.Entry<K,V> next;
703 LinkedHashMap.Entry<K,V> current;
704 int expectedModCount;
705
706 LinkedHashIterator() {
707 next = head;
708 expectedModCount = modCount;
709 current = null;
710 }
711
712 public final boolean hasNext() {
713 return next != null;
714 }
715
716 final LinkedHashMap.Entry<K,V> nextNode() {
717 LinkedHashMap.Entry<K,V> e = next;
718 if (modCount != expectedModCount)
719 throw new ConcurrentModificationException();
720 if (e == null)
721 throw new NoSuchElementException();
722 current = e;
723 next = e.after;
724 return e;
725 }
726
727 public final void remove() {
728 Node<K,V> p = current;
729 if (p == null)
730 throw new IllegalStateException();
731 if (modCount != expectedModCount)
732 throw new ConcurrentModificationException();
733 current = null;
734 removeNode(p.hash, p.key, null, false, false);
735 expectedModCount = modCount;
736 }
737 }
738
739 final class LinkedKeyIterator extends LinkedHashIterator
740 implements Iterator<K> {
741 public final K next() { return nextNode().getKey(); }
742 }
743
744 final class LinkedValueIterator extends LinkedHashIterator
745 implements Iterator<V> {
746 public final V next() { return nextNode().value; }
747 }
748
749 final class LinkedEntryIterator extends LinkedHashIterator
750 implements Iterator<Map.Entry<K,V>> {
751 public final Map.Entry<K,V> next() { return nextNode(); }
752 }
753
754
755 }
756