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; Entry(int hash, K key, V value, Node<K,V> next)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 linkNodeLast(LinkedHashMap.Entry<K,V> p)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 transferLinks(LinkedHashMap.Entry<K,V> src, LinkedHashMap.Entry<K,V> 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 reinitialize()250 void reinitialize() { 251 super.reinitialize(); 252 head = tail = null; 253 } 254 newNode(int hash, K key, V value, Node<K,V> e)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 replacementNode(Node<K,V> p, Node<K,V> next)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 newTreeNode(int hash, K key, V value, Node<K,V> next)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 replacementTreeNode(Node<K,V> p, Node<K,V> next)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 afterNodeRemoval(Node<K,V> e)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 afterNodeInsertion(boolean evict)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 afterNodeAccess(Node<K,V> e)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 internalWriteEntries(java.io.ObjectOutputStream s)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 */ LinkedHashMap(int initialCapacity, float loadFactor)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 */ LinkedHashMap(int initialCapacity)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 */ LinkedHashMap()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 */ LinkedHashMap(Map<? extends K, ? extends V> m)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 */ LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)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 */ containsValue(Object value)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 */ get(Object key)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 */ getOrDefault(Object key, V defaultValue)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 */ clear()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 */ removeEldestEntry(Map.Entry<K,V> eldest)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 */ keySet()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> { size()540 public final int size() { return size; } clear()541 public final void clear() { LinkedHashMap.this.clear(); } iterator()542 public final Iterator<K> iterator() { 543 return new LinkedKeyIterator(); 544 } contains(Object o)545 public final boolean contains(Object o) { return containsKey(o); } remove(Object key)546 public final boolean remove(Object key) { 547 return removeNode(hash(key), key, null, false, true) != null; 548 } spliterator()549 public final Spliterator<K> spliterator() { 550 return Spliterators.spliterator(this, Spliterator.SIZED | 551 Spliterator.ORDERED | 552 Spliterator.DISTINCT); 553 } forEach(Consumer<? super K> action)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 */ values()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> { size()593 public final int size() { return size; } clear()594 public final void clear() { LinkedHashMap.this.clear(); } iterator()595 public final Iterator<V> iterator() { 596 return new LinkedValueIterator(); 597 } contains(Object o)598 public final boolean contains(Object o) { return containsValue(o); } spliterator()599 public final Spliterator<V> spliterator() { 600 return Spliterators.spliterator(this, Spliterator.SIZED | 601 Spliterator.ORDERED); 602 } forEach(Consumer<? super V> action)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 */ entrySet()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>> { size()639 public final int size() { return size; } clear()640 public final void clear() { LinkedHashMap.this.clear(); } iterator()641 public final Iterator<Map.Entry<K,V>> iterator() { 642 return new LinkedEntryIterator(); 643 } contains(Object o)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 } remove(Object o)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 } spliterator()661 public final Spliterator<Map.Entry<K,V>> spliterator() { 662 return Spliterators.spliterator(this, Spliterator.SIZED | 663 Spliterator.ORDERED | 664 Spliterator.DISTINCT); 665 } forEach(Consumer<? super Map.Entry<K,V>> action)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 forEach(BiConsumer<? super K, ? super V> action)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 replaceAll(BiFunction<? super K, ? super V, ? extends V> function)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 LinkedHashIterator()706 LinkedHashIterator() { 707 next = head; 708 expectedModCount = modCount; 709 current = null; 710 } 711 hasNext()712 public final boolean hasNext() { 713 return next != null; 714 } 715 nextNode()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 remove()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> { next()741 public final K next() { return nextNode().getKey(); } 742 } 743 744 final class LinkedValueIterator extends LinkedHashIterator 745 implements Iterator<V> { next()746 public final V next() { return nextNode().value; } 747 } 748 749 final class LinkedEntryIterator extends LinkedHashIterator 750 implements Iterator<Map.Entry<K,V>> { next()751 public final Map.Entry<K,V> next() { return nextNode(); } 752 } 753 754 755 } 756