001/* 002 * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025package Torello.Java.ReadOnly; 026 027import java.util.*; 028 029import java.util.function.BiConsumer; 030import java.util.function.BiFunction; 031import java.util.function.Consumer; 032import java.util.function.Function; 033 034/** 035 * A Copy of Java's {@code HashMap} class; used for building a {@link ReadOnlyHashMap}. 036 * Maintains <I>an internal and inaccessible {@code HashMap<E>} instance</I>. 037 * 038 * <EMBED CLASS=globalDefs DATA-JDK=HashMap> 039 * <EMBED CLASS='external-html' DATA-A_AN=a DATA-FILE-ID=BUILDERS> 040 * 041 * @param <K> the type of keys maintained by this map 042 * @param <V> the type of mapped values 043 * @see ReadOnlyHashMap 044 */ 045@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_BUILDER") 046public final class ROHashMapBuilder<K, V> 047 extends HashMap<K, V> 048 implements Cloneable, java.io.Serializable 049{ 050 // ******************************************************************************************** 051 // ******************************************************************************************** 052 // Fields & Builder Stuff 053 // ******************************************************************************************** 054 // ******************************************************************************************** 055 056 057 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 058 protected static final long serialVersionUID = 1; 059 060 // Exception messages need this 061 private static final String ROHM = "HashMap"; 062 063 private boolean built = false; 064 065 // Mimics the C++ Concept of "Friend Class". This badge is utilized by the "build()" method 066 // directly below this inner-class declaration. It is the only place where this declaration is 067 // actually used anywhere. This prohibits access to the constructor that is used to anybody 068 // else 069 070 static class AccessBadge { private AccessBadge() { } } 071 private static final AccessBadge friendClassBadge = new AccessBadge(); 072 073 /** 074 * Simply transfers {@code 'this'} instance' internal {@code HashMap} to the 075 * {@code ReadOnlyHashMap} Wrapper-Class. 076 * 077 * @return a newly constructed {@code ReadOnlyHashMap} "Wrapper-Class", shielding the internal 078 * {@code 'hashMap'} private-field from any modification. 079 */ 080 public ReadOnlyHashMap<K, V> build() 081 { 082 this.built = true; 083 084 return (size() == 0) 085 ? ReadOnlyHashMap.emptyROHM() 086 : new ReadOnlyHashMap<>(this, friendClassBadge); 087 } 088 089 090 // ******************************************************************************************** 091 // ******************************************************************************************** 092 // Modified Constructors 093 // ******************************************************************************************** 094 // ******************************************************************************************** 095 096 097 /** 098 * Constructs an empty {@code ROHashMapBuilder} with the specified initial capacity and load 099 * factor. 100 * 101 * <BR /><BR />To create a {@code ROHashMapBuilder} with an initial capacity that accommodates 102 * an expected number of mappings, use {@link #newROHashMapBuilder(int) newROHashMapBuilder}. 103 * 104 * @param initialCapacity the initial capacity 105 * @param loadFactor the load factor 106 * @throws IllegalArgumentException if the initial capacity is negative or the load factor is 107 * nonpositive 108 */ 109 public ROHashMapBuilder(int initialCapacity, float loadFactor) 110 { super(initialCapacity, loadFactor); } 111 112 /** 113 * Constructs an empty {@code ROHashMapBuilder} with the specified initial capacity and the 114 * default load factor (0.75). 115 * 116 * <BR /><BR />To create a {@code ROHashMapBuilder} with an initial capacity that accommodates 117 * an expected number of mappings, use {@link #newROHashMapBuilder(int) newROHashMapBuilder}. 118 * 119 * @param initialCapacity the initial capacity. 120 * @throws IllegalArgumentException if the initial capacity is negative. 121 */ 122 public ROHashMapBuilder(int initialCapacity) 123 { super(initialCapacity); } 124 125 /** 126 * Constructs an empty {@code ROHashMapBuilder} with the default initial capacity (16) and the 127 * default load factor (0.75). 128 */ 129 public ROHashMapBuilder() 130 { super(); } 131 132 /** 133 * Constructs a new {@code ROHashMapBuilder} with the same mappings as the specified 134 * {@code Map}. The {@code ROHashMapBuilder} is created with default load factor (0.75) and an 135 * initial capacity sufficient to hold the mappings in the specified {@code Map}. 136 * 137 * @param m the map whose mappings are to be placed in this map 138 * @throws NullPointerException if the specified map is null 139 */ 140 public ROHashMapBuilder(Map<? extends K, ? extends V> m) 141 { super(m); } 142 143 /** 144 * Creates a new, empty {@code ROHashMapBuilder} suitable for the expected number of mappings. 145 * The returned map uses the default load factor of 0.75, and its initial capacity is generally 146 * large enough so that the expected number of mappings can be added without resizing the map. 147 * 148 * @param numMappings the expected number of mappings 149 * @param <K> the type of keys maintained by the new map 150 * @param <V> the type of mapped values 151 * @return the newly created map 152 * @throws IllegalArgumentException if numMappings is negative 153 */ 154 public static <K, V> ROHashMapBuilder<K, V> newROHashMapBuilder(int numMappings) 155 { 156 if (numMappings < 0) 157 throw new IllegalArgumentException("Negative number of mappings: " + numMappings); 158 159 return new ROHashMapBuilder<>(calculateHashMapCapacity(numMappings)); 160 } 161 162 // Copied from JDK-21, java.util.HashMap 163 // Calculate initial capacity for HashMap based classes, from expected size and default load 164 // factor (0.75). 165 166 private static int calculateHashMapCapacity(int numMappings) 167 { return (int) Math.ceil(numMappings / (double) /* DEFAULT_LOAD_FACTOR */ 0.75f); } 168 169 170 // ******************************************************************************************** 171 // ******************************************************************************************** 172 // Original JDK Methods 173 // ******************************************************************************************** 174 // ******************************************************************************************** 175 176 177 /** 178 * Associates the specified value with the specified key in this map. If the map previously 179 * contained a mapping for the key, the old value is replaced. 180 * 181 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 182 * 183 * @param key key with which the specified value is to be associated 184 * @param value value to be associated with the specified key 185 * 186 * @return the previous value associated with {@code key}, or {@code null} if there was no 187 * mapping for {@code key}. (A {@code null} return can also indicate that the map previously 188 * associated {@code null} with {@code key}.) 189 */ 190 public V put(K key, V value) 191 { 192 if (this.built) throw new AttemptedModificationException(ROHM); 193 return super.put(key, value); 194 } 195 196 /** 197 * Copies all of the mappings from the specified map to this map. These mappings will replace 198 * any mappings that this map had for any of the keys currently in the specified map. 199 * 200 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 201 * 202 * @param m mappings to be stored in this map 203 * @throws NullPointerException if the specified map is null 204 */ 205 public void putAll(Map<? extends K, ? extends V> m) 206 { 207 if (this.built) throw new AttemptedModificationException(ROHM); 208 super.putAll(m); 209 } 210 211 /** 212 * Removes the mapping for the specified key from this map if present. 213 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 214 * @param key key whose mapping is to be removed from the map 215 * 216 * @return the previous value associated with {@code key}, or {@code null} if there was no 217 * mapping for {@code key}. (A {@code null} return can also indicate that the map previously 218 * associated {@code null} with {@code key}.) 219 */ 220 public V remove(Object key) 221 { 222 if (this.built) throw new AttemptedModificationException(ROHM); 223 return super.remove(key); 224 } 225 226 /** 227 * Removes all of the mappings from this map. The map will be empty after this call returns. 228 * 229 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 230 */ 231 public void clear() 232 { 233 if (this.built) throw new AttemptedModificationException(ROHM); 234 super.clear(); 235 } 236 237 238 // ******************************************************************************************** 239 // ******************************************************************************************** 240 // Overrides of JDK8 Map extension methods 241 // ******************************************************************************************** 242 // ******************************************************************************************** 243 244 245 /** 246 * If the specified key is not already associated with a value (or is mapped to {@code null}) 247 * associates it with the given value and returns {@code null}, else returns the current value. 248 * 249 * <BR /><BR />The default implementation is equivalent to, for this {@code map}: 250 * 251 * <BR /><DIV CLASS=SNIP>{@code 252 * V v = map.get(key); 253 * 254 * if (v == null) v = map.put(key, value); 255 * 256 * return v; 257 * }</DIV> 258 * 259 * <BR /><BR />The default implementation makes no guarantees about synchronization or 260 * atomicity properties of this method. Any implementation providing atomicity guarantees must 261 * override this method and document its concurrency properties. 262 * 263 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 264 * 265 * @param key key with which the specified value is to be associated 266 * @param value value to be associated with the specified key 267 * 268 * @return the previous value associated with the specified key, or {@code null} if there was 269 * no mapping for the key. (A {@code null} return can also indicate that the map previously 270 * associated {@code null} with the key, if the implementation supports null values.) 271 * 272 * @throws UnsupportedOperationException if the {@code put} operation is not supported by this 273 * map 274 * 275 * @throws ClassCastException if the key or value is of an inappropriate type for this map 276 * 277 * @throws NullPointerException if the specified key or value is null, and this map does not 278 * permit null keys or values 279 * 280 * @throws IllegalArgumentException if some property of the specified key or value prevents it 281 * from being stored in this map 282 */ 283 public V putIfAbsent(K key, V value) 284 { 285 if (this.built) throw new AttemptedModificationException(ROHM); 286 return super.putIfAbsent(key, value); 287 } 288 289 /** 290 * Removes the entry for the specified key only if it is currently mapped to the specified 291 * value. 292 * 293 * <BR /><BR />The default implementation is equivalent to, for this {@code map}: 294 * 295 * <BR /><DIV CLASS=SNIP>{@code 296 * if (map.containsKey(key) && Objects.equals(map.get(key), value)) 297 * { 298 * map.remove(key); 299 * return true; 300 * } 301 * 302 * return false; 303 * }</DIV> 304 * 305 * <BR /><BR />The default implementation makes no guarantees about synchronization or 306 * atomicity properties of this method. Any implementation providing atomicity guarantees must 307 * override this method and document its concurrency properties. 308 * 309 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 310 * 311 * @param key key with which the specified value is associated 312 * @param value value expected to be associated with the specified key 313 * @return {@code true} if the value was removed 314 * 315 * @throws UnsupportedOperationException if the {@code remove} operation is not supported by 316 * this map 317 * 318 * @throws ClassCastException if the key or value is of an inappropriate type for this map 319 * 320 * @throws NullPointerException if the specified key or value is null, and this map does not 321 * permit null keys or values 322 */ 323 public boolean remove(Object key, Object value) 324 { 325 if (this.built) throw new AttemptedModificationException(ROHM); 326 return super.remove(key, value); 327 } 328 329 /** 330 * Replaces the entry for the specified key only if currently mapped to the specified value. 331 * 332 * <BR /><BR />The default implementation is equivalent to, for this {@code map}: 333 * 334 * <DIV CLASS=SNIP>{@code 335 * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) 336 * { 337 * map.put(key, newValue); 338 * return true; 339 * } 340 * 341 * return false; 342 * }</DIV> 343 * 344 * <BR /><BR />The default implementation does not throw {@code NullPointerException} for maps 345 * that do not support null values if oldValue is null unless newValue is also null. 346 * 347 * <BR /><BR />The default implementation makes no guarantees about synchronization or 348 * atomicity properties of this method. Any implementation providing atomicity guarantees must 349 * override this method and document its concurrency properties. 350 * 351 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 352 * 353 * @param key key with which the specified value is associated 354 * @param oldValue value expected to be associated with the specified key 355 * @param newValue value to be associated with the specified key 356 * @return {@code TRUE} if the value was replaced 357 * 358 * @throws UnsupportedOperationException if the {@code put} operation is not supported by this 359 * map 360 * 361 * @throws ClassCastException if the class of a specified key or value prevents it from being 362 * stored in this map 363 * 364 * @throws NullPointerException if a specified key or newValue is null, and this map does not 365 * permit null keys or values 366 * 367 * @throws NullPointerException if oldValue is null and this map does not permit null values 368 * 369 * @throws IllegalArgumentException if some property of a specified key or value prevents it 370 * from being stored in this map 371 */ 372 public boolean replace(K key, V oldValue, V newValue) 373 { 374 if (this.built) throw new AttemptedModificationException(ROHM); 375 return super.replace(key, oldValue, newValue); 376 } 377 378 /** 379 * Replaces the entry for the specified key only if it is currently mapped to some value. 380 * 381 * <BR /><BR />The default implementation is equivalent to, for this {@code map}: 382 * 383 * <BR /><DIV CLASS=SNIP>{@code 384 * if (map.containsKey(key)) return map.put(key, value); 385 * return null; 386 * }</DIV> 387 * 388 * <BR /><BR />The default implementation makes no guarantees about synchronization or 389 * atomicity properties of this method. Any implementation providing atomicity guarantees must 390 * override this method and document its concurrency properties. 391 * 392 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 393 * 394 * @param key key with which the specified value is associated 395 * @param value value to be associated with the specified key 396 * 397 * @return the previous value associated with the specified key, or {@code null} if there was 398 * no mapping for the key. (A {@code null} return can also indicate that the map previously 399 * associated {@code null} with the key, if the implementation supports null values.) 400 * 401 * @throws UnsupportedOperationException if the {@code put} operation is not supported by this 402 * map 403 * 404 * @throws ClassCastException if the class of the specified key or value prevents it from being 405 * stored in this map 406 * 407 * @throws NullPointerException if the specified key or value is null, and this map does not 408 * permit null keys or values 409 * 410 * @throws IllegalArgumentException if some property of the specified key or value prevents it 411 * from being stored in this map 412 */ 413 public V replace(K key, V value) 414 { 415 if (this.built) throw new AttemptedModificationException(ROHM); 416 return super.replace(key, value); 417 } 418 419 /** 420 * If the specified key is not already associated with a value (or is mapped to null), attempts 421 * to compute its value using the given mapping function and enters it into this map unless 422 * null. 423 * 424 * <BR /><BR />If the mapping function returns null, no mapping is recorded. If the mapping 425 * function itself throws an (unchecked) exception, the exception is rethrown, and no mapping 426 * is recorded. The most common usage is to construct a new object serving as an initial mapped 427 * value or memoized result, as in: 428 * 429 * <BR /><DIV CLASS=SNIP>{@code 430 * map.computeIfAbsent(key, k -> new Value(f(k))); 431 * }</DIV> 432 * 433 * <BR /><BR />Or to implement a multi-value map, {@code Map<K,Collection<V>>}, supporting 434 * multiple values per key: 435 * 436 * <BR /><DIV CLASS=SNIP>{@code 437 * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v); 438 * }</DIV> 439 * 440 * <BR /><BR />The mapping function should not modify this map during computation. 441 * 442 * <BR /><BR />This method will, on a best-effort basis, throw a 443 * {@link ConcurrentModificationException} if it is detected that the mapping function modifies 444 * this map during computation. 445 * 446 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 447 * 448 * @param key key with which the specified value is to be associated 449 * @param mappingFunction the mapping function to compute a value 450 * 451 * @return the current (existing or computed) value associated with the specified key, or null 452 * if the computed value is null 453 * 454 * @throws ConcurrentModificationException if it is detected that the mapping function modified 455 * this map 456 */ 457 public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) 458 { 459 if (this.built) throw new AttemptedModificationException(ROHM); 460 return super.computeIfAbsent(key, mappingFunction); 461 } 462 463 /** 464 * If the value for the specified key is present and non-null, attempts to compute a new 465 * mapping given the key and its current mapped value. 466 * 467 * <BR /><BR />If the remapping function returns null, the mapping is removed. If the remapping 468 * function itself throws an (unchecked) exception, the exception is rethrown, and the current 469 * mapping is left unchanged. 470 * 471 * <BR /><BR />The remapping function should not modify this map during computation. 472 * 473 * <BR /><BR />This method will, on a best-effort basis, throw a 474 * {@link ConcurrentModificationException} if it is detected that the remapping function 475 * modifies this map during computation. 476 * 477 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 478 * 479 * @param key key with which the specified value is to be associated 480 * @param remappingFunction the remapping function to compute a value 481 * @return the new value associated with the specified key, or null if none 482 * @throws ConcurrentModificationException if it is detected that the remapping function 483 * modified this map 484 */ 485 public V computeIfPresent 486 (K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 487 { 488 if (this.built) throw new AttemptedModificationException(ROHM); 489 return super.computeIfPresent(key, remappingFunction); 490 } 491 492 /** 493 * Attempts to compute a mapping for the specified key and its current mapped value (or null if 494 * there is no current mapping). For example, to either create or append a String msg to a 495 * value mapping: 496 * 497 * <BR ><DIV CLASS=SNIP>{@code 498 * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg)) 499 * }</DIV> 500 * 501 * <BR /><BR />(Method merge() is often simpler to use for such purposes.) 502 * 503 * <BR /><BR />If the remapping function returns null, the mapping is removed (or remains 504 * absent if initially absent). If the remapping function itself throws an (unchecked) 505 * exception, the exception is rethrown, and the current mapping is left unchanged. 506 * 507 * <BR /><BR />The remapping function should not modify this map during computation. 508 * 509 * <BR /><BR />This method will, on a best-effort basis, throw a 510 * {@link ConcurrentModificationException} if it is detected that the remapping function 511 * modifies this map during computation. 512 * 513 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 514 * 515 * @param key key with which the specified value is to be associated 516 * @param remappingFunction the remapping function to compute a value 517 * @return the new value associated with the specified key, or null if none 518 * 519 * @throws ConcurrentModificationException if it is detected that the remapping function 520 * modified this map 521 */ 522 public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 523 { 524 if (this.built) throw new AttemptedModificationException(ROHM); 525 return super.compute(key, remappingFunction); 526 } 527 528 /** 529 * If the specified key is not already associated with a value or is associated with null, 530 * associates it with the given non-null value. Otherwise, replaces the associated value with 531 * the results of the given remapping function, or removes if the result is null. This method 532 * may be of use when combining multiple mapped values for a key. For example, to either create 533 * or append a String msg to a value mapping: 534 * 535 * <BR /><DIV CLASS=SNIP>{@code 536 * map.merge(key, msg, String::concat) 537 * }</DIV> 538 * 539 * <BR /><BR />If the remapping function returns null, the mapping is removed. If the remapping 540 * function itself throws an (unchecked) exception, the exception is rethrown, and the current 541 * mapping is left unchanged. 542 * 543 * <BR /><BR />The remapping function should not modify this map during computation. 544 * 545 * <BR /><BR />This method will, on a best-effort basis, throw a 546 * {@code ConcurrentModificationException} if it is detected that the remapping function 547 * modifies this map during computation. 548 * 549 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 550 * 551 * @param key key with which the resulting value is to be associated 552 * 553 * @param value the non-null value to be merged with the existing value associated with the key 554 * or, if no existing value or a null value is associated with the key, to be associated with 555 * the key 556 * 557 * @parma remappingFunction the remapping function to recompute a value if present 558 * 559 * @return the new value associated with the specified key, or null if no value is associated 560 * with the key 561 * 562 * @throws ConcurrentModificationException if it is detected that the remapping function 563 * modified this map 564 */ 565 public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) 566 { 567 if (this.built) throw new AttemptedModificationException(ROHM); 568 return super.merge(key, value, remappingFunction); 569 } 570 571 /** 572 * Replaces each entry's value with the result of invoking the given function on that entry 573 * until all entries have been processed or the function throws an exception. Exceptions thrown 574 * by the function are relayed to the caller. 575 * 576 * <BR /><BR />The implementation is equivalent to: 577 * 578 * <BR /><DIV CLASS=SNIP>{@code 579 * for (Map.Entry<K, V> entry : map.entrySet()) 580 * entry.setValue(function.apply(entry.getKey(), entry.getValue())); 581 * }</DIV> 582 * 583 * <BR /><BR />No guarantees about synchronization or atomicity properties of this method. 584 * 585 * <EMBED DATA-TYPE=HashMap CLASS='external-html' DATA-FILE-ID=MUTATOR> 586 * 587 * @param function the function to apply to each entry 588 * 589 * @throws UnsupportedOperationException if the set operation is not supported by this map's 590 * entry set iterator. 591 * 592 * @throws ClassCastException if the class of a replacement value prevents it from being 593 * stored in this map (optional) 594 * 595 * @throws NullPointerException if the specified function is null, or if a replacement value is 596 * null and this map does not permit null values (optional) 597 * 598 * @throws IllegalArgumentException if some property of a replacement value prevents it from 599 * being stored in this map (optional) 600 * 601 * @throws ConcurrentModificationException - if an entry is found to be removed during 602 * iteration 603 */ 604 public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) 605 { 606 if (this.built) throw new AttemptedModificationException(ROHM); 607 super.replaceAll(function); 608 } 609 610 611 // ******************************************************************************************** 612 // ******************************************************************************************** 613 // Methods inherited from class java.util.HashMap 614 // ******************************************************************************************** 615 // ******************************************************************************************** 616 617 618 // containsKey, containsValue, entrySet, forEach, get, getOrDefault, isEmpty, keySet, size, 619 // values 620 // 621 // Introspection Only: containsKey, containsValue, forEach, get, getOrDefault, isEmpty, size 622 // Mutator or Potential Mutator: entrySet, keySet, values 623 // 624 // *** OTHER INHERITED METHODS - ALL READ-ONLY METHODS *** 625 // 626 // Methods inherited from class java.util.AbstractMap: hashCode, toString 627 // Methods inherited from interface java.util.Map: hashCode 628 629 /** 630 * Restricts a back-door into the underlying data-structure. 631 * <EMBED CLASS='external-html'DATA-RET_TYPE=Set DATA-FILE-ID=UNMODIFIABLE> 632 * @return a {@code java.util.Set} that cannot modify this {@code HashMap-Builder} 633 */ 634 public Set<Map.Entry<K, V>> entrySet() 635 { return Collections.unmodifiableSet(super.entrySet()); } 636 637 Set<Map.Entry<K, V>> _entrySet(ReadOnlyHashMap.AccessBadge friendClassBadge) 638 { return super.entrySet(); } 639 640 /** 641 * Restricts a back-door into the underlying data-structure. 642 * <EMBED CLASS='external-html'DATA-RET_TYPE=Set DATA-FILE-ID=UNMODIFIABLE> 643 * @return a {@code java.util.Set} that cannot modify this {@code HashMap-Builder} 644 */ 645 public Set<K> keySet() 646 { return Collections.unmodifiableSet(super.keySet()); } 647 648 Set<K> _keySet(ReadOnlyHashMap.AccessBadge friendClassBadge) 649 { return super.keySet(); } 650 651 /** 652 * Restricts a back-door into the underlying data-structure. 653 * <EMBED CLASS='external-html'DATA-RET_TYPE=Collection DATA-FILE-ID=UNMODIFIABLE> 654 * @return a {@code java.util.Collection} that cannot modify this {@code HashMap-Builder} 655 */ 656 public Collection<V> values() 657 { return Collections.unmodifiableCollection(super.values()); } 658 659 Collection<V> _values(ReadOnlyHashMap.AccessBadge friendClassBadge) 660 { return super.values(); } 661 662 663 // ******************************************************************************************** 664 // ******************************************************************************************** 665 // java.lang.Object & Cloneable 666 // ******************************************************************************************** 667 // ******************************************************************************************** 668 669 670 /** 671 * Compares the specified Object with this Builder for equality, as per the definition in the 672 * original class {@code java.util.HashMap}. Ignores the private field {@code 'built'}. If 673 * {@code 'this'} has not been built, but {@code 'o'} has been, that fact is ignored during the 674 * equality-comparison. 675 * 676 * @param o object to be compared for equality with this {@code ROHashMapBuilder} instance 677 * @return true if the specified Object is equal to this Builder 678 */ 679 public synchronized boolean equals(Object o) 680 { 681 if (this == o) return true; 682 if (! (o instanceof ROHashMapBuilder)) return false; 683 return super.equals((HashMap) o); 684 } 685 686 /** 687 * Clones this instance' of {@code ROHashMapBuilder}. 688 * 689 * <BR /><BR />The clone that's returned has had it's internal {@code 'built'} boolean-flag set 690 * {@code FALSE} 691 * 692 * @return a clone of this builder 693 */ 694 public synchronized ROHashMapBuilder<K, V> clone() 695 { return new ROHashMapBuilder<>(this); } 696 697 private ROHashMapBuilder(ROHashMapBuilder<K, V> rohmb) 698 { super(rohmb); this.built=false; } 699} 700