001/* 002 * Copyright (c) 1997, 2018, 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.io.Serializable; 028 029import java.util.*; 030 031import java.util.function.BiConsumer; 032import java.util.function.BiFunction; 033import java.util.function.Consumer; 034import java.util.function.Predicate; 035import java.util.function.Function; 036 037import Torello.Java.ReadOnly.ROTreeMapBuilder; 038import Torello.Java.Additional.Tuple2; 039 040/** 041 * Immutable Wrapper for <CODE>java.util.TreeMap</CODE>, found in the "Java Collections 042 * Framework". 043 * 044 * <EMBED CLASS=globalDefs DATA-JDK=TreeMap> 045 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS> 046 * 047 * @param <K> the type of keys maintained by this map 048 * @param <V> the type of mapped values 049 */ 050@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN") 051@SuppressWarnings("unchecked") 052public class ReadOnlyTreeMap<K, V> 053 // extends AbstractReadOnlyMap<K, V> 054 implements ReadOnlyNavigableMap<K, V>, java.io.Serializable 055{ 056 // ******************************************************************************************** 057 // ******************************************************************************************** 058 // Protected & Private Fields, Methods, Statics 059 // ******************************************************************************************** 060 // ******************************************************************************************** 061 062 063 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 064 protected static final long serialVersionUID = 1; 065 066 // Minor Optimization where new TreeMap's that have no contents always re-use this static 067 // instance. Since this instance is completely empty, the Raw-Types things is irrelevant. 068 069 @SuppressWarnings("rawtypes") 070 private static final TreeMap EMPTY_TREE_MAP = new TreeMap(); 071 072 // Singleton & Empty ReadOnlyTreeMap, Uses the "Supplier Constructor" 073 @SuppressWarnings("rawtypes") 074 private static final ReadOnlyTreeMap EMPTY_READONLY_TREE_MAP = 075 new ReadOnlyTreeMap(EMPTY_TREE_MAP); 076 077 // The actual TreeMap used by this instance. 078 private final TreeMap<K, V> treeMap; 079 080 // TRUE => This was built using the class ROTreeMapBuilder 081 // FALSE => This was built using the clone() of a standard java.util.TreeMap constructor 082 083 private final boolean fromBuilderOrTreeMap; 084 085 // Mimics the C++ Keyword/Concept of "Friend Class". Is "Friends With" ROTreeMapBuilder 086 static class AccessBadge { private AccessBadge() { } } 087 private static final AccessBadge friendClassBadge = new AccessBadge(); 088 089 090 // ******************************************************************************************** 091 // ******************************************************************************************** 092 // Builder, Acess-Badge Constructor - and Static "Empty" getter (which is used by the builder) 093 // ******************************************************************************************** 094 // ******************************************************************************************** 095 096 097 /** 098 * Returns an empty, <B STYLE='color: red;'>singleton</B>, instance of {@code ReadOnlyTreeMap}. 099 * @param <X> Returned {@link ReadOnlyMap}'s Key-Type. 100 * @param <Y> Returned {@link ReadOnlyMap}'s Value-Type. 101 * 102 * @return An empty map. Since this map is both empty & read-only, a raw-type singleton 103 * will suffice for all operations offered by this clas. 104 */ 105 public static <X, Y> ReadOnlyTreeMap<X, Y> emptyROTM() 106 { return (ReadOnlyTreeMap<X, Y>) EMPTY_READONLY_TREE_MAP; } 107 108 // To all the readers out there following along: The "AccessBadge" thing is just a slightly 109 // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class". It means this 110 // constructor is (for all intents and purposes) a private-constructor, except for the class 111 // ROTreeMapBuilder 112 // 113 // This is the Constructor used by the Builder. It has a "Zero-Size" Optimization 114 115 ReadOnlyTreeMap(ROTreeMapBuilder<K, V> rotmb, ROTreeMapBuilder.AccessBadge badge) 116 { 117 Objects.requireNonNull(badge, "Access Badge is null. Requires Friend-Class Badge"); 118 119 this.fromBuilderOrTreeMap = true; 120 this.treeMap = rotmb; 121 } 122 123 124 // ******************************************************************************************** 125 // ******************************************************************************************** 126 // Modified-Original Constructors 127 // ******************************************************************************************** 128 // ******************************************************************************************** 129 130 131 /** 132 * Copies the contents of parameter {@code 'map'}, and saves saves it, thereby guaranteeing 133 * {@code 'this'} instance is Read-Only and fully-shielded from outside modification. 134 * 135 * @param map The {@code Map} to be copied into {@code 'this'} instance internal and private 136 * {@code 'treeMap'} field. 137 */ 138 public ReadOnlyTreeMap(Map<K, V> map) 139 { 140 this.fromBuilderOrTreeMap = false; 141 142 this.treeMap = (map.size() == 0) 143 ? ((TreeMap<K, V>) EMPTY_TREE_MAP) 144 : new TreeMap<K, V>(map); 145 } 146 147 /** 148 * If only a small amount of processing needs to be done on the contents of some Java 149 * Map, and using an entire Builder-Class seems disproportionately complex - <I>this 150 * constructor can convert any Java {@code Map} into a {@code ReadOnlyTreeMap}, using 151 * a simple {@code 'mapTranslator'}</I>. 152 * 153 * @param <X> The Key-Type of the User-Provided {@code Map}. 154 * @param <Y> The Value-Type of the User-Provided {@code Map}. 155 * 156 * @param refHolder This must a non-null instance of {@link Tuple2}. The provided 157 * {@code Consumer} is just that, a {@code 'Consumer'} rather than a {@code 'Function'}, since 158 * the results of each translation must be assigned to the values inside this tuple in order 159 * for them to be inserted into this {@code ReadOnlyTreeMap}. 160 * 161 * @param map Any Java {@code Map}. 162 * 163 * @param mapTranslator A function for mapping the iterated elements of Map-Types {@code 'X'} 164 * and {@code 'Y'}, into the actual {@code TreeMap's} Key-Type {@code 'K'}, and Value-Type 165 * {@code 'V'}. The results of this translation must be placed into the fields inside 166 * {@code 'refHolder'}. 167 * 168 * <BR /><BR />If this parameter is passed null, this method will throw a 169 * {@code NullPointerException}. 170 * 171 * @param filter An optional filter that can be used to prevent & prohibit any chosen 172 * elements from input {@code 'map'} from being inserted into {@code 'this'} 173 * {@code ReadOnlyTreeMap}. 174 * 175 * <BR /><BR />This parameter may be passed null, and if it is, it will be silently ignored, 176 * and all entries present inside {@code 'map'} will be processed and inserted into 177 * {@code 'this'} 178 * 179 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 180 * 181 * @throws NullPointerException if either parameter {@code 'i'} or parameter 182 * {@code 'mapTranslator'} is passed null. 183 */ 184 public <X, Y> ReadOnlyTreeMap( 185 Tuple2<K, V> refHolder, 186 Map<X, Y> map, 187 Consumer<Map.Entry<X, Y>> mapTranslator, 188 Predicate<Map.Entry<X, Y>> filter, 189 Comparator<? super K> comparator 190 ) 191 { 192 Objects.requireNonNull(refHolder, ROHelpers.NULL_MSG + "'refHolder'"); 193 Objects.requireNonNull(mapTranslator, ROHelpers.NULL_MSG + "'mapTranslator'"); 194 195 fromBuilderOrTreeMap = false; 196 197 TreeMap<K, V> treeMap = (comparator != null) 198 ? new TreeMap<>(comparator) 199 : new TreeMap<>(); 200 201 if (filter == null) 202 203 for (Map.Entry<X, Y> entry : map.entrySet()) 204 { 205 mapTranslator.accept(entry); 206 treeMap.put(refHolder.a, refHolder.b); 207 } 208 209 else for (Map.Entry<X, Y> entry : map.entrySet()) 210 { 211 if (! filter.test(entry)) continue; 212 mapTranslator.accept(entry); 213 treeMap.put(refHolder.a, refHolder.b); 214 } 215 216 // Empty Optimization (throw away, completely, the reference, use static-constant) 217 this.treeMap = (treeMap.size() == 0) ? ((TreeMap<K, V>) EMPTY_TREE_MAP) : treeMap; 218 } 219 220 221 // ******************************************************************************************** 222 // ******************************************************************************************** 223 // New Constructors, January 2024 224 // ******************************************************************************************** 225 // ******************************************************************************************** 226 227 228 /** 229 * Constructs an instance of {@code ReadOnlyTreeMap} that contains the keys present in 230 * parameter {@code 'keys'}, and values generated by {@code 'valueMapper'} - using each of the 231 * {@code 'keys'} as input. 232 * 233 * <EMBED CLASS='external-html' DATA-FILE-ID=LOOK_AT_IT> 234 * 235 * @param keys Any Java {@code Iterable} instance. 236 * @param valueMapper A user provided function to compute a map value, based on a map key. 237 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=MAP_ITERABLE_FILTER> 238 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 239 * 240 * @throws NullPointerException if either {@code 'keys'} or {@code 'valueMapper'} are passed 241 * null. 242 */ 243 public ReadOnlyTreeMap( 244 Iterable<? extends K> keys, 245 Function<? super K, ? extends V> valueMapper, 246 Predicate<? super K> filter, 247 Comparator<? super K> comparator 248 ) 249 { 250 Objects.requireNonNull(keys, ROHelpers.NULL_MSG + "'keys'"); 251 Objects.requireNonNull(valueMapper, ROHelpers.NULL_MSG + "'valueMapper'"); 252 253 fromBuilderOrTreeMap = false; 254 255 TreeMap<K, V> treeMap = (comparator != null) 256 ? new TreeMap<>(comparator) 257 : new TreeMap<>(); 258 259 if (filter == null) 260 for (K key : keys) 261 treeMap.put(key, valueMapper.apply(key)); 262 263 else 264 for (K key : keys) 265 if (filter.test(key)) 266 treeMap.put(key, valueMapper.apply(key)); 267 268 // Empty Optimization (throw away, completely, the reference, use static-constant) 269 this.treeMap = (treeMap.size() == 0) ? ((TreeMap<K, V>) EMPTY_TREE_MAP) : treeMap; 270 } 271 272 /** 273 * Constructs an instance of {@code ReadOnlyTreeMap} that has been populated by the Key-Value 274 * Pairs left in {@code 'refHolder'} by each invocation of the {@code Runnable} parameter 275 * {@code 'computeNextEntry'}. Key-Value Pairs are inserted until an invocation of the 276 * {@code Runnable} leaves null in {@code refHolder.a} and {@code refHolder.b} 277 * 278 * <EMBED CLASS='external-html' DATA-FILE-ID=LOOK_AT_IT> 279 * 280 * @param refHolder <EMBED CLASS='external-html' DATA-FILE-ID=REF_HOLDER> 281 * @param computeNextEntry <EMBED CLASS='external-html' DATA-FILE-ID=COMPUTE_NEXT_RUN> 282 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 283 * 284 * @throws NullPointerException if either {@code 'refHolder'} or {@code 'computeNextEntry'} are 285 * passed null. 286 */ 287 public ReadOnlyTreeMap( 288 Tuple2<K, V> refHolder, 289 Runnable computeNextEntry, 290 Comparator<? super K> comparator 291 ) 292 { 293 Objects.requireNonNull(refHolder, ROHelpers.NULL_MSG + "'refHolder'"); 294 Objects.requireNonNull(computeNextEntry, ROHelpers.NULL_MSG + "'computeNextEntry'"); 295 296 fromBuilderOrTreeMap = false; 297 298 TreeMap<K, V> treeMap = (comparator != null) 299 ? new TreeMap<>(comparator) 300 : new TreeMap<>(); 301 302 do 303 { 304 computeNextEntry.run(); 305 if ((refHolder.a == null) && (refHolder.b == null)) break; 306 treeMap.put(refHolder.a, refHolder.b); 307 } 308 while (true); 309 310 // Empty Optimization (throw away, completely, the reference, use static-constant) 311 this.treeMap = (treeMap.size() == 0) ? ((TreeMap<K, V>) EMPTY_TREE_MAP) : treeMap; 312 } 313 314 /** 315 * Populates an instance of {@code ReadOnlyTreeMap} by iterating the input {@code 'source'} 316 * iterable, and passing each value returned by that {@code Iterator} to the 317 * {@code 'computeNextEntry'} Java {@code Consumer}. 318 * 319 * <BR /><BR />It is the programmer's responsibility to properly place each Key-Value Pair 320 * that is intending to be inserted into the final {@code Map} instance into the 321 * {@code 'refHolder'} instance. After each invocation of {@code 'computeNextEntry'}, this 322 * constructor's logic will retrieve the values within {@code 'refHolder.a'} and 323 * {@code 'refHolder.b'} and insert them into this instance internal {@code TreeMap}. 324 * 325 * <EMBED CLASS='external-html' DATA-FILE-ID=LOOK_AT_IT> 326 * 327 * @param <X> The type of the elements inside {@code 'source'} 328 * @param source Any Java {@code Iterable} instance. 329 * @param refHolder <EMBED CLASS='external-html' DATA-FILE-ID=REF_HOLDER> 330 * @param computeNextEntry <EMBED CLASS='external-html' DATA-FILE-ID=COMPUTE_NEXT_CONS> 331 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=MAP_ITERABLE_FILTER> 332 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 333 * 334 * @throws NullPointerException if either {@code 'refHolder'}, {@code 'computeNextEntry'} or 335 * {@code 'source'} are passed null. 336 */ 337 public <X> ReadOnlyTreeMap( 338 Iterable<X> source, 339 Tuple2<K, V> refHolder, 340 Consumer<? super X> computeNextEntry, 341 Predicate<? super X> filter, 342 Comparator<? super K> comparator 343 ) 344 { 345 Objects.requireNonNull(refHolder, ROHelpers.NULL_MSG + "'refHolder'"); 346 Objects.requireNonNull(computeNextEntry, ROHelpers.NULL_MSG + "'computeNextEntry'"); 347 348 fromBuilderOrTreeMap = false; 349 350 TreeMap<K, V> treeMap = (comparator != null) 351 ? new TreeMap<>(comparator) 352 : new TreeMap<>(); 353 354 X x; // temp var 355 Iterator<X> iter = source.iterator(); 356 357 if (filter == null) 358 359 while (iter.hasNext()) 360 { 361 computeNextEntry.accept(iter.next()); 362 treeMap.put(refHolder.a, refHolder.b); 363 } 364 365 else 366 367 while (iter.hasNext()) 368 if (filter.test(x = iter.next())) 369 { 370 computeNextEntry.accept(x); 371 treeMap.put(refHolder.a, refHolder.b); 372 } 373 374 // Empty Optimization (throw away, completely, the reference, use static-constant) 375 this.treeMap = (treeMap.size() == 0) ? ((TreeMap<K, V>) EMPTY_TREE_MAP) : treeMap; 376 } 377 378 379 // ******************************************************************************************** 380 // ******************************************************************************************** 381 // Array Constructors, March 2024 382 // ******************************************************************************************** 383 // ******************************************************************************************** 384 385 386 /** 387 * Retrieves elements from the VarArgs Generic-Array parameter {@code 'elements'}, and 388 * subsequently invokes the {@code 'computeNextEntry'} processor to populate this 389 * {@code ReadOnlyTreeMap}. 390 * 391 * @param <X> The type of array parameter {@code 'elements'} 392 * @param refHolder <EMBED CLASS='external-html' DATA-FILE-ID=REF_HOLDER> 393 * @param computeNextEntry <EMBED CLASS='external-html' DATA-FILE-ID=ARR_COMPUTE_NEXT_CONS> 394 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=MAP_ARRAY_FILTER> 395 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 396 * @param elements Any Generic VarArgs-Array 397 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 398 * 399 * @throws NullPointerException if either {@code 'refHolder'} or {@code 'computeNextEntry'} 400 * are passed null 401 */ 402 public <X> ReadOnlyTreeMap( 403 Tuple2<K, V> refHolder, 404 Consumer<? super X> computeNextEntry, 405 Predicate<? super X> filter, 406 Comparator<? super K> comparator, 407 X... elements 408 ) 409 { 410 Objects.requireNonNull(refHolder, ROHelpers.NULL_MSG + "'refHolder'"); 411 Objects.requireNonNull(computeNextEntry, ROHelpers.NULL_MSG + "'computeNextEntry'"); 412 413 this.fromBuilderOrTreeMap = false; 414 415 TreeMap<K, V> treeMap = (comparator != null) ? new TreeMap<>(comparator) : new TreeMap<>(); 416 417 if (filter == null) for (X e : elements) 418 { 419 computeNextEntry.accept(e); 420 treeMap.put(refHolder.a, refHolder.b); 421 } 422 423 else for (X x : elements) if (filter.test(x)) 424 { 425 computeNextEntry.accept(x); 426 treeMap.put(refHolder.a, refHolder.b); 427 } 428 429 // Empty Optimization (throw away, completely, the reference, use static-constant) 430 this.treeMap = (treeMap.size() == 0) ? ((TreeMap<K, V>) EMPTY_TREE_MAP) : treeMap; 431 } 432 433 /** 434 * Retrieves elements from the Java Primitive-Array parameter {@code 'primitiveArray'}, and 435 * subsequently invokes the {@code 'computeNextEntry'} processor to populate this 436 * {@code ReadOnlyTreeMap}. 437 * 438 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=PRED_FILT_PRIM> 439 * @param computeNextEntry <EMBED CLASS='external-html' DATA-FILE-ID=ARR_COMPUTE_NEXT_CONS> 440 * @param refHolder <EMBED CLASS='external-html' DATA-FILE-ID=REF_HOLDER> 441 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 442 * @param primitiveArray Any Java Primitive-Array 443 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 444 * 445 * @throws NullPointerException if either {@code 'refHolder'} or {@code 'computeNextEntry'} 446 * are passed null 447 * 448 */ 449 public <X> ReadOnlyTreeMap( 450 Predicate<?> filter, 451 Consumer<?> computeNextEntry, 452 Tuple2<K, V> refHolder, 453 Comparator<? super K> comparator, 454 Object primitiveArray 455 ) 456 { 457 Objects.requireNonNull(refHolder, ROHelpers.NULL_MSG + "'refHolder'"); 458 Objects.requireNonNull(computeNextEntry, ROHelpers.NULL_MSG + "'computeNextEntry'"); 459 460 this.fromBuilderOrTreeMap = false; 461 462 TreeMap<K, V> treeMap = ROHelpers.buildROMap( 463 primitiveArray, 464 (int arrayLen) -> (comparator != null) ? new TreeMap<>(comparator) : new TreeMap<>(), 465 filter, 466 refHolder, 467 computeNextEntry 468 ); 469 470 // Empty Optimization (throw away, completely, the reference, use static-constant) 471 this.treeMap = (treeMap.size() == 0) ? ((TreeMap<K, V>) EMPTY_TREE_MAP) : treeMap; 472 } 473 474 475 // ******************************************************************************************** 476 // ******************************************************************************************** 477 // Convert to java.util Types 478 // ******************************************************************************************** 479 // ******************************************************************************************** 480 481 482 /** 483 * Clone's {@code 'this'} instance internal {@code TreeMap<K, V>} field, and returns it. 484 * <EMBED CLASS='external-html' DATA-TYPE=TreeMap DATA-FILE-ID=CLONE_TO> 485 * 486 * @return An independent, mutable copy of {@code 'this'} instance internal 487 * {@code TreeMap<K, V>} data-structure. 488 */ 489 public TreeMap<K, V> cloneToTreeMap() 490 { 491 if (! fromBuilderOrTreeMap) return (TreeMap<K, V>) this.treeMap.clone(); 492 493 TreeMap<K, V> ret = new TreeMap<K, V>(); 494 495 for (Map.Entry<K, V> e : 496 ((ROTreeMapBuilder<K, V>) this.treeMap)._entrySet(friendClassBadge)) 497 498 ret.put(e.getKey(), e.getValue()); 499 500 return ret; 501 } 502 503 /** 504 * Invokes {@code java.util.Collections.unmodifiableMap} on the internal {@code TreeMap}. 505 * <EMBED CLASS='external-html' DATA-RET_TYPE=Map DATA-FILE-ID=WRAP_TO_IMMUTABLE> 506 * 507 * @return A {@code Map} which adheres to the JDK interface {@code java.util.Map}, but throws 508 * an {@code UnsupportedOperationException} if a user attempts to invoke a Mutator-Method on 509 * the returned instance. 510 */ 511 public Map<K, V> wrapToImmutableMap() 512 { return Collections.unmodifiableMap(this.treeMap); } 513 514 515 // ******************************************************************************************** 516 // ******************************************************************************************** 517 // Original JDK Methods, java.util.TreeMap 518 // ******************************************************************************************** 519 // ******************************************************************************************** 520 521 522 /** 523 * Returns the number of key-value mappings in this map. 524 * @return the number of key-value mappings in this map 525 */ 526 public int size() 527 { return this.treeMap.size(); } 528 529 /** 530 * Returns {@code TRUE} if this map contains a mapping for the specified key. 531 * 532 * @param key key whose presence in this map is to be tested 533 * @return {@code TRUE} if this map contains a mapping for the specified key 534 * 535 * @throws ClassCastException if the specified key cannot be compared with the keys currently 536 * in the map 537 * 538 * @throws NullPointerException if the specified key is null and this map uses natural 539 * ordering, or its comparator does not permit null keys 540 */ 541 public boolean containsKey(Object key) 542 { return this.treeMap.containsKey(key); } 543 544 /** 545 * Returns {@code TRUE} if this map maps one or more keys to the specified value. More 546 * formally, returns {@code TRUE} if and only if this map contains at least one mapping to a 547 * value {@code v} such that {@code (value==null ? v==null : value.equals(v))}. 548 * 549 * @param value value whose presence in this map is to be tested 550 * @return {@code TRUE} if a mapping to {@code value} exists; {@code FALSE} otherwise 551 */ 552 public boolean containsValue(Object value) 553 { return this.treeMap.containsValue(value); } 554 555 /** 556 * Returns the value to which the specified key is mapped, or {@code null} if this map contains 557 * no mapping for the key. 558 * 559 * <BR /><BR />More formally, if this map contains a mapping from a key {@code k} to a value 560 * {@code v} such that {@code key} compares equal to {@code k} according to the map's ordering, 561 * then this method returns {@code v}; otherwise it returns {@code null}. (There can be at 562 * most one such mapping.) 563 * 564 * <BR /><BR />A return value of {@code null} does not <em>necessarily</em> indicate that the 565 * map contains no mapping for the key; it's also possible that the map explicitly maps the key 566 * to {@code null}. The {@link #containsKey containsKey} operation may be used to distinguish 567 * these two cases. 568 * 569 * @throws ClassCastException if the specified key cannot be compared with the keys currently 570 * in the map 571 * 572 * @throws NullPointerException if the specified key is null and this map uses natural 573 * ordering, or its comparator does not permit null keys 574 */ 575 public V get(Object key) 576 { return this.treeMap.get(key); } 577 578 public Comparator<? super K> comparator() 579 { return this.treeMap.comparator(); } 580 581 /** @throws NoSuchElementException {@inheritDoc} */ 582 public K firstKey() 583 { return this.treeMap.firstKey(); } 584 585 /** @throws NoSuchElementException {@inheritDoc} */ 586 public K lastKey() 587 { return this.treeMap.lastKey(); } 588 589 public ReadOnlyMap.Entry<K,V> firstEntry() 590 { return new EntryImpl<>(this.treeMap.firstEntry()); } 591 592 public ReadOnlyMap.Entry<K,V> lastEntry() 593 { return new EntryImpl<>(this.treeMap.lastEntry()); } 594 595 /** 596 * @throws ClassCastException {@inheritDoc} 597 * 598 * @throws NullPointerException if the specified key is null and this map uses natural 599 * ordering, or its comparator does not permit null keys 600 */ 601 public ReadOnlyMap.Entry<K,V> lowerEntry(K key) 602 { return new EntryImpl<>(this.treeMap.lowerEntry(key)); } 603 604 /** 605 * @throws ClassCastException {@inheritDoc} 606 * 607 * @throws NullPointerException if the specified key is null and this map uses natural 608 * ordering, or its comparator does not permit null keys 609 */ 610 public K lowerKey(K key) 611 { return this.treeMap.lowerKey(key); } 612 613 /** 614 * @throws ClassCastException {@inheritDoc} 615 * 616 * @throws NullPointerException if the specified key is null and this map uses natural 617 * ordering, or its comparator does not permit null keys 618 */ 619 public ReadOnlyMap.Entry<K,V> floorEntry(K key) 620 { return new EntryImpl<>(this.treeMap.floorEntry(key)); } 621 622 /** 623 * @throws ClassCastException {@inheritDoc} 624 * 625 * @throws NullPointerException if the specified key is null and this map uses natural 626 * ordering, or its comparator does not permit null keys 627 */ 628 public K floorKey(K key) 629 { return this.treeMap.floorKey(key); } 630 631 /** 632 * @throws ClassCastException {@inheritDoc} 633 * 634 * @throws NullPointerException if the specified key is null and this map uses natural 635 * ordering, or its comparator does not permit null keys 636 */ 637 public ReadOnlyMap.Entry<K,V> ceilingEntry(K key) 638 { return new EntryImpl<>(this.treeMap.ceilingEntry(key)); } 639 640 /** 641 * @throws ClassCastException {@inheritDoc} 642 * 643 * @throws NullPointerException if the specified key is null and this map uses natural 644 * ordering, or its comparator does not permit null keys 645 */ 646 public K ceilingKey(K key) 647 { return this.treeMap.ceilingKey(key); } 648 649 /** 650 * @throws ClassCastException {@inheritDoc} 651 * 652 * @throws NullPointerException if the specified key is null and this map uses natural 653 * ordering, or its comparator does not permit null keys 654 */ 655 public ReadOnlyMap.Entry<K,V> higherEntry(K key) 656 { return new EntryImpl<>(this.treeMap.higherEntry(key)); } 657 658 /** 659 * @throws ClassCastException {@inheritDoc} 660 * 661 * @throws NullPointerException if the specified key is null and this map uses natural 662 * ordering, or its comparator does not permit null keys 663 */ 664 public K higherKey(K key) 665 { return this.treeMap.higherKey(key); } 666 667 /** Returns a {@link ReadOnlySet} view of the keys contained in this map. */ 668 public ReadOnlySet<K> keySet() 669 { 670 return InterfaceBuilder.toReadOnlySet( 671 fromBuilderOrTreeMap 672 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._keySet(friendClassBadge) 673 : this.treeMap.keySet() 674 ); 675 } 676 677 public ReadOnlyNavigableSet<K> navigableKeySet() 678 { 679 return InterfaceBuilder.toReadOnlyNavigableSet( 680 fromBuilderOrTreeMap 681 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._navigableKeySet(friendClassBadge) 682 : this.treeMap.navigableKeySet() 683 ); 684 } 685 686 public ReadOnlyNavigableSet<K> descendingKeySet() 687 { 688 return InterfaceBuilder.toReadOnlyNavigableSet( 689 fromBuilderOrTreeMap 690 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._descendingKeySet(friendClassBadge) 691 : this.treeMap.descendingKeySet() 692 ); 693 } 694 695 /** Returns a {@link ReadOnlyCollection} view of the values contained in this map. */ 696 public ReadOnlyCollection<V> values() 697 { 698 return InterfaceBuilder.toReadOnlyCollection( 699 fromBuilderOrTreeMap 700 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._values(friendClassBadge) 701 : this.treeMap.values() 702 ); 703 } 704 705 /** 706 * Returns a {@link ReadOnlySet} view of the mappings contained in this map. 707 * 708 * @return At the moment, a {@link ReadOnlyTreeSet} is arbitrarily used for the type of the 709 * returned instance 710 */ 711 public ReadOnlySet<ReadOnlyMap.Entry<K, V>> entrySet() 712 { 713 return ROHelpers.toReadOnlyEntrySet( 714 fromBuilderOrTreeMap 715 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._entrySet(friendClassBadge) 716 : this.treeMap.entrySet() 717 ); 718 } 719 720 public ReadOnlyNavigableMap<K, V> descendingMap() 721 { 722 return InterfaceBuilder.toReadOnlyNavigableMap( 723 fromBuilderOrTreeMap 724 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._descendingMap(friendClassBadge) 725 : this.treeMap.descendingMap() 726 ); 727 } 728 729 /** 730 * @throws ClassCastException {@inheritDoc} 731 * 732 * @throws NullPointerException if {@code fromKey} or {@code toKey} is null and this map uses 733 * natural ordering, or its comparator does not permit null keys 734 * 735 * @throws IllegalArgumentException {@inheritDoc} 736 */ 737 public ReadOnlyNavigableMap<K,V> subMap( 738 K fromKey, boolean fromInclusive, 739 K toKey, boolean toInclusive 740 ) 741 { 742 return InterfaceBuilder.toReadOnlyNavigableMap( 743 fromBuilderOrTreeMap 744 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._subMap 745 (fromKey, fromInclusive, toKey, toInclusive, friendClassBadge) 746 : this.treeMap.subMap(fromKey, fromInclusive, toKey, toInclusive) 747 ); 748 } 749 750 /** 751 * @throws ClassCastExceptionv{@inheritDoc} 752 * 753 * @throws NullPointerException if {@code toKey} is nullvand this map uses natural ordering, or 754 * its comparator does not permit null keys 755 * 756 * @throws IllegalArgumentException {@inheritDoc} 757 */ 758 public ReadOnlyNavigableMap<K,V> headMap(K toKey, boolean inclusive) 759 { 760 return InterfaceBuilder.toReadOnlyNavigableMap( 761 fromBuilderOrTreeMap 762 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._headMap 763 (toKey, inclusive, friendClassBadge) 764 : this.treeMap.headMap(toKey, inclusive) 765 ); 766 } 767 768 /** 769 * @throws ClassCastException {@inheritDoc} 770 * 771 * @throws NullPointerException if {@code fromKey} is null and this map uses natural ordering, 772 * or its comparator does not permit null keys 773 * 774 * @throws IllegalArgumentException {@inheritDoc} 775 */ 776 public ReadOnlyNavigableMap<K,V> tailMap(K fromKey, boolean inclusive) 777 { 778 return InterfaceBuilder.toReadOnlyNavigableMap( 779 fromBuilderOrTreeMap 780 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._tailMap 781 (fromKey, inclusive, friendClassBadge) 782 : this.treeMap.tailMap(fromKey, inclusive) 783 ); 784 } 785 786 /** 787 * @throws ClassCastException {@inheritDoc} 788 * 789 * @throws NullPointerException if {@code fromKey} or {@code toKey} is null and this map uses 790 * natural ordering, or its comparator does not permit null keys 791 * 792 * @throws IllegalArgumentException {@inheritDoc} 793 */ 794 public ReadOnlySortedMap<K,V> subMap(K fromKey, K toKey) 795 { 796 return InterfaceBuilder.toReadOnlySortedMap( 797 fromBuilderOrTreeMap 798 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._subMap 799 (fromKey, toKey, friendClassBadge) 800 : this.treeMap.subMap(fromKey, toKey) 801 ); 802 } 803 804 /** 805 * @throws ClassCastException {@inheritDoc} 806 * 807 * @throws NullPointerException if {@code toKey} is null and this map uses natural ordering, or 808 * its comparator does not permit null keys 809 * 810 * @throws IllegalArgumentException {@inheritDoc} 811 */ 812 public ReadOnlySortedMap<K,V> headMap(K toKey) 813 { 814 return InterfaceBuilder.toReadOnlySortedMap( 815 fromBuilderOrTreeMap 816 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._headMap(toKey, friendClassBadge) 817 : this.treeMap.headMap(toKey) 818 ); 819 } 820 821 /** 822 * @throws ClassCastException {@inheritDoc} 823 * 824 * @throws NullPointerException if {@code fromKey} is null and this map uses natural ordering, 825 * or its comparator does not permit null keys 826 * 827 * @throws IllegalArgumentException {@inheritDoc} 828 */ 829 public ReadOnlySortedMap<K,V> tailMap(K fromKey) 830 { 831 return InterfaceBuilder.toReadOnlySortedMap( 832 fromBuilderOrTreeMap 833 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._tailMap(fromKey, friendClassBadge) 834 : this.treeMap.tailMap(fromKey) 835 ); 836 } 837 838 @Override 839 public void forEach(BiConsumer<? super K, ? super V> action) 840 { this.treeMap.forEach(action); } 841 842 843 // ******************************************************************************************** 844 // ******************************************************************************************** 845 // Misc Stuff that is defined in a super-class - for java.util, but not for Java.ReadOnly 846 // ******************************************************************************************** 847 // ******************************************************************************************** 848 849 850 public boolean isEmpty() 851 { return this.treeMap.isEmpty(); } 852 853 854 // ******************************************************************************************** 855 // ******************************************************************************************** 856 // java.lang.Object 857 // ******************************************************************************************** 858 // ******************************************************************************************** 859 860 861 /** 862 * Returns a {@code String} representation of this map. The {@code String} representation 863 * consists of a list of key-value mappings in the order returned by the map's entrySet view's 864 * iterator, enclosed in braces ({@code "{}"}). Adjacent mappings are separated by the 865 * characters {@code ", "} (comma and space). Each key-value mapping is rendered as the key 866 * followed by an equals sign ({@code "="}) followed by the associated value. Keys and values 867 * are converted to {@code String's} as by {@code String.valueOf(Object)}. 868 * 869 * @return a {@code String} representation of this {@code TreeMap} 870 */ 871 public String toString() 872 { 873 return ROHelpers.toString( 874 this.treeMap, // if the map contains itself, it is needed for printing purposes 875 fromBuilderOrTreeMap 876 ? ((ROTreeMapBuilder<K, V>) this.treeMap)._entrySet(friendClassBadge) 877 : this.treeMap.entrySet() 878 ); 879 } 880 881 /** 882 * Compares the specified Object with this Map for equality, as per the definition in the 883 * class {@code java.util.TreeMap}. 884 * 885 * @param o object to be compared for equality with this {@code ReadOnlyTreeMap}. 886 * @return {@code TRUE} if the specified Object is equal to this map 887 */ 888 public boolean equals(Object o) 889 { return ROHelpers.roMapEq(this, o); } 890 891 /** 892 * Returns the hash code value for this Map as per the definition in the class 893 * {@code java.util.TreeMap}. 894 */ 895 public int hashCode() 896 { return this.treeMap.hashCode(); } 897 898}