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 */ 025 026package Torello.Java.ReadOnly; 027 028import java.util.*; 029 030import java.util.function.BiConsumer; 031import java.io.Serializable; 032 033/** 034 * Immutable variant of Java Collections Framework interface 035 * <CODE>java.util.Map<K, V></CODE>. 036 * 037 * <EMBED CLASS='external-html' DATA-JDK=ReadOnlyMap DATA-FILE-ID=INTERFACES> 038 * 039 * @param <K> the type of keys maintained by this map 040 * @param <V> the type of mapped values 041 */ 042@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_INTERFACE") 043public interface ReadOnlyMap<K, V> 044{ 045 // ******************************************************************************************** 046 // ******************************************************************************************** 047 // Query Operations 048 // ******************************************************************************************** 049 // ******************************************************************************************** 050 051 052 /** 053 * Returns the number of key-value mappings in this map. If the map contains more than 054 * {@code Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}. 055 * 056 * @return the number of key-value mappings in this map 057 */ 058 int size(); 059 060 /** 061 * Returns {@code TRUE} if this map contains no key-value mappings. 062 * @return {@code TRUE} if this map contains no key-value mappings 063 */ 064 boolean isEmpty(); 065 066 /** 067 * Returns {@code TRUE} if this map contains a mapping for the specified key. More formally, 068 * returns {@code TRUE} if and only if this map contains a mapping for a key {@code k} such 069 * that {@code Objects.equals(key, k)}. (There can be at most one such mapping.) 070 * 071 * @param key key whose presence in this map is to be tested 072 * @return {@code TRUE} if this map contains a mapping for the specified key 073 * 074 * @throws ClassCastException if the key is of an inappropriate type for this map 075 * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 076 * 077 * @throws NullPointerException if the specified key is null and this map does not permit null 078 * keys (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 079 */ 080 boolean containsKey(Object key); 081 082 /** 083 * Returns {@code TRUE} if this map maps one or more keys to the specified value. More 084 * formally, returns {@code TRUE} if and only if this map contains at least one mapping to a 085 * value {@code v} such that {@code Objects.equals(value, v)}. This operation will probably 086 * require time linear in the map size for most implementations of the {@code Map} interface. 087 * 088 * @param value value whose presence in this map is to be tested 089 * @return {@code TRUE} if this map maps one or more keys to the specified value 090 * 091 * @throws ClassCastException if the value is of an inappropriate type for 092 * this map (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 093 * 094 * @throws NullPointerException if the specified value is null and this map does not permit 095 * null values 096 * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 097 */ 098 boolean containsValue(Object value); 099 100 /** 101 * Returns the value to which the specified key is mapped, or {@code null} if this map contains 102 * no mapping for the key. 103 * 104 * <BR /><BR />More formally, if this map contains a mapping from a key {@code k} to a value 105 * {@code v} such that {@code Objects.equals(key, k)}, then this method returns {@code v}; 106 * otherwise it returns {@code null}. (There can be at most one such mapping.) 107 * 108 * <BR /><BR />If this map permits null values, then a return value of {@code null} does not 109 * <i>necessarily</i> indicate that the map contains no mapping for the key; it's also possible 110 * that the map explicitly maps the key to {@code null}. The {@link #containsKey containsKey} 111 * operation may be used to distinguish these two cases. 112 * 113 * @param key the key whose associated value is to be returned 114 * 115 * @return the value to which the specified key is mapped, or {@code null} if this map contains 116 * no mapping for the key 117 * 118 * @throws ClassCastException if the key is of an inappropriate type for this map 119 * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 120 * 121 * @throws NullPointerException if the specified key is null and this map does not permit null 122 * keys (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 123 */ 124 V get(Object key); 125 126 127 // ******************************************************************************************** 128 // ******************************************************************************************** 129 // Views 130 // ******************************************************************************************** 131 // ******************************************************************************************** 132 133 134 /** 135 * Returns a {@link ReadOnlySet} view of the keys contained in this map. The set is backed by 136 * the map, so changes to the map are reflected in the set, and vice-versa. 137 * 138 * @return a set view of the keys contained in this map 139 */ 140 ReadOnlySet<K> keySet(); 141 142 /** 143 * Returns a {@link ReadOnlyCollection} view of the values contained in this map. 144 * @return a collection view of the values contained in this map 145 */ 146 ReadOnlyCollection<V> values(); 147 148 /** 149 * Returns a {@link ReadOnlySet} view of the mappings contained in this map. 150 * @return a set view of the mappings contained in this map 151 */ 152 ReadOnlySet<ReadOnlyMap.Entry<K, V>> entrySet(); 153 154 /** 155 * A map entry (key-value pair). 156 * 157 * <BR /><BR />An Entry may also be obtained from a map's entry-set view by other means, for 158 * example, using the 159 * {@link ReadOnlySet#parallelStream parallelStream}, 160 * {@link ReadOnlySet#stream stream}, 161 * {@link ReadOnlySet#spliterator spliterator} 162 * methods, any of the 163 * {@link ReadOnlySet#toArray toArray} 164 * overloads, or by copying the entry-set view into another collection. 165 * 166 * <BR /><BR />In addition, an Entry may be obtained directly from a map, for example via calls 167 * to methods directly on the {@link ReadOnlyNavigableMap} interface. 168 * 169 * @param <K> the type of the key 170 * @param <V> the type of the value 171 * 172 * @see ReadOnlyMap#entrySet() 173 */ 174 interface Entry<K, V> 175 { 176 /** 177 * Returns the key corresponding to this entry. 178 * @return the key corresponding to this entry 179 */ 180 K getKey(); 181 182 /** 183 * Returns the value corresponding to this entry. 184 * @return the value corresponding to this entry 185 */ 186 V getValue(); 187 188 /** 189 * Compares the specified object with this entry for equality. 190 * Returns {@code TRUE} if the given object is also a map entry and 191 * the two entries represent the same mapping. More formally, two 192 * entries {@code e1} and {@code e2} represent the same mapping 193 * if 194 * 195 * <BR /><DIV CLASS=SNIP>{@code 196 * (e1.getKey()==null 197 * ? e2.getKey()==null 198 * : e1.getKey().equals(e2.getKey())) 199 * && 200 * (e1.getValue()==null 201 * ? e2.getValue()==null 202 * : e1.getValue().equals(e2.getValue())) 203 * }</DIV> 204 * 205 * <BR /><BR />This ensures that the {@code equals} method works properly across different 206 * implementations of the {@code ReadOnlyMap.Entry} interface. 207 * 208 * @param o object to be compared for equality with this map entry 209 * @return {@code TRUE} if the specified object is equal to this map entry 210 */ 211 boolean equals(Object o); 212 213 /** 214 * Returns the hash code value for this map entry. The hash code of a map entry {@code e} 215 * is defined to be: 216 * 217 * <BR /><DIV CLASS=SNIP>{@code 218 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 219 * (e.getValue()==null ? 0 : e.getValue().hashCode()) 220 * }</DIV> 221 * 222 * <BR /><BR />This ensures that {@code e1.equals(e2)} implies that 223 * {@code e1.hashCode()==e2.hashCode()} for any two Entries {@code e1} and {@code e2}, as 224 * required by the general contract of {@code Object.hashCode}. 225 * 226 * @return the hash code value for this map entry 227 * @see #equals(Object) 228 */ 229 int hashCode(); 230 231 /** 232 * Returns a comparator that compares {@link ReadOnlyMap.Entry} in natural order on key. 233 * 234 * <BR /><BR />The returned comparator is serializable and throws 235 * {@code NullPointerException} when comparing an entry with a null key. 236 * 237 * @param <K> the {@link Comparable} type of then map keys 238 * @param <V> the type of the map values 239 * @return a comparator that compares {@link ReadOnlyMap.Entry} in natural order on key. 240 */ 241 public static <K extends Comparable<? super K>, V> 242 Comparator<ReadOnlyMap.Entry<K, V>> 243 comparingByKey() 244 { 245 return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable) 246 (c1, c2) -> c1.getKey().compareTo(c2.getKey()); 247 } 248 249 /** 250 * Returns a comparator that compares {@link ReadOnlyMap.Entry} in natural order on value. 251 * 252 * <BR /><BR />The returned comparator is serializable and throws 253 * {@code NullPointerException} when comparing an entry with null values. 254 * 255 * @param <K> the type of the map keys 256 * @param <V> the {@code Comparable} type of the map values 257 * @return a comparator that compares {@link ReadOnlyMap.Entry} in natural order on value. 258 * @see Comparable 259 */ 260 public static <K, V extends Comparable<? super V>> 261 Comparator<ReadOnlyMap.Entry<K, V>> 262 comparingByValue() 263 { 264 return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable) 265 (c1, c2) -> c1.getValue().compareTo(c2.getValue()); 266 } 267 268 /** 269 * Returns a comparator that compares {@link ReadOnlyMap.Entry} by key using the given 270 * {@code Comparator}. 271 * 272 * <BR /><BR />The returned comparator is serializable if the specified comparator is also 273 * serializable. 274 * 275 * @param <K> the type of the map keys 276 * @param <V> the type of the map values 277 * @param cmp the key {@code Comparator} 278 * @return a comparator that compares {@link ReadOnlyMap.Entry} by the key. 279 */ 280 public static <K, V> 281 Comparator<ReadOnlyMap.Entry<K, V>> 282 comparingByKey(Comparator<? super K> cmp) 283 { 284 Objects.requireNonNull(cmp); 285 return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable) 286 (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); 287 } 288 289 /** 290 * Returns a comparator that compares {@link ReadOnlyMap.Entry} by value using the given 291 * {@code Comparator}. 292 * 293 * <BR /><BR />The returned comparator is serializable if the specified comparator is also 294 * serializable. 295 * 296 * @param <K> the type of the map keys 297 * @param <V> the type of the map values 298 * @param cmp the value {@link Comparator} 299 * @return a comparator that compares {@link ReadOnlyMap.Entry} by the value. 300 */ 301 public static <K, V> 302 Comparator<ReadOnlyMap.Entry<K, V>> 303 comparingByValue(Comparator<? super V> cmp) 304 { 305 Objects.requireNonNull(cmp); 306 return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable) 307 (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); 308 } 309 } 310 311 312 // ******************************************************************************************** 313 // ******************************************************************************************** 314 // Comparison and hashing 315 // ******************************************************************************************** 316 // ******************************************************************************************** 317 318 319 /** 320 * Compares the specified object with this map for equality. Returns {@code TRUE} if the given 321 * object is also a map and the two maps represent the same mappings. More formally, two maps 322 * {@code m1} and {@code m2} represent the same mappings if 323 * {@code m1.entrySet().equals(m2.entrySet())}. This ensures that the {@code equals} method 324 * works properly across different implementations of the {@code Map} interface. 325 * 326 * @param o object to be compared for equality with this map 327 * @return {@code TRUE} if the specified object is equal to this map 328 */ 329 boolean equals(Object o); 330 331 /** 332 * Returns the hash code value for this map. The hash code of a map is defined to be the sum 333 * of the hash codes of each entry in the map's {@code entrySet()} view. This ensures that 334 * {@code m1.equals(m2)} implies that {@code m1.hashCode()==m2.hashCode()} for any two maps 335 * {@code m1} and {@code m2}, as required by the general contract of {@code Object.hashCode}. 336 * 337 * @return the hash code value for this map 338 * @see ReadOnlyMap.Entry#hashCode() 339 * @see #equals(Object) 340 */ 341 int hashCode(); 342 343 344 // ******************************************************************************************** 345 // ******************************************************************************************** 346 // Defaultable methods 347 // ******************************************************************************************** 348 // ******************************************************************************************** 349 350 351 /** 352 * Returns the value to which the specified key is mapped, or {@code defaultValue} if this map 353 * contains no mapping for the key. 354 * 355 * @param key the key whose associated value is to be returned 356 * @param defaultValue the default mapping of the key 357 * 358 * @return the value to which the specified key is mapped, or {@code defaultValue} if this map 359 * contains no mapping for the key 360 * 361 * @throws ClassCastException if the key is of an inappropriate type for this map 362 * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 363 * 364 * @throws NullPointerException if the specified key is null and this map does not permit null 365 * keys 366 * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>) 367 */ 368 default V getOrDefault(Object key, V defaultValue) 369 { 370 V v; 371 return (((v = get(key)) != null) || containsKey(key)) 372 ? v 373 : defaultValue; 374 } 375 376 /** 377 * Performs the given action for each entry in this map until all entries have been processed 378 * or the action throws an exception. Unless otherwise specified by the implementing class, 379 * actions are performed in the order of entry set iteration (if an iteration order is 380 * specified.) Exceptions thrown by the action are relayed to the caller. 381 * 382 * <BR /><BR />The default implementation is equivalent to, for this {@code map}: 383 * 384 * <BR /><DIV CLASS=SNIP>{@code 385 * for (ReadOnlyMap.Entry<K, V> entry : map.entrySet()) 386 * action.accept(entry.getKey(), entry.getValue()); 387 * }</DIV> 388 * 389 * <BR /><BR />The default implementation makes no guarantees about synchronization or 390 * atomicity properties of this method. Any implementation providing atomicity guarantees must 391 * override this method and document its concurrency properties. 392 * 393 * @param action The action to be performed for each entry 394 * @throws NullPointerException if the specified action is null 395 */ 396 default void forEach(BiConsumer<? super K, ? super V> action) 397 { 398 Objects.requireNonNull(action); 399 400 for (ReadOnlyMap.Entry<K, V> entry : entrySet()) 401 { 402 K k; 403 V v; 404 405 try 406 { 407 k = entry.getKey(); 408 v = entry.getValue(); 409 } 410 411 catch (IllegalStateException ise) 412 { 413 // this usually means the entry is no longer in the map. 414 // throw new ConcurrentModificationException(ise); 415 416 throw new Torello.Java.UnreachableError(); 417 } 418 419 action.accept(k, v); 420 } 421 } 422 423 /** 424 * Copies the contents of {@code 'this'} ReadOnlyMap into the user-provided {@code 'map'}. 425 * Utilizes the {@code java.util.Map} method {@code put(K key, V value)}. 426 * 427 * @param map Any instance of java.util.Map 428 * @see #forEach(BiConsumer) 429 */ 430 default void copyIntoMap(Map<? super K, ? super V> map) 431 { this.forEach((K k, V v) -> map.put(k, v)); } 432 433 434 // ******************************************************************************************** 435 // ******************************************************************************************** 436 // MAP-KEYS: contains - using Var-Args Arrays 437 // ******************************************************************************************** 438 // ******************************************************************************************** 439 440 441 /** 442 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 443 * <B STYLE='color: red;'>contains a matching key for every one of the elements</B> in 444 * Var-Args Parameter {@code 'elements'} 445 * 446 * @param elements a list of elements 447 * 448 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 449 * every element in {@code 'elements'} 450 */ 451 default boolean containsKeyAND(Object... elements) 452 { 453 ReadOnlySet<K> keys = this.keySet(); 454 for (Object elem : elements) if (! keys.contains(elem)) return false; 455 return true; 456 } 457 458 /** 459 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 460 * <B STYLE='color: red;'>does not contain any key that matches any of the elements</B> in 461 * Var-Args Parameter {@code 'elements'} 462 * 463 * @param elements a list of elements 464 * 465 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 466 * none of the elements in {@code 'elements'} 467 */ 468 default boolean containsKeyNAND(Object... elements) 469 { 470 ReadOnlySet<K> keys = this.keySet(); 471 for (Object elem : elements) if (keys.contains(elem)) return false; 472 return true; 473 } 474 475 /** 476 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 477 * <B STYLE='color: red;'>contains at least one key that matches at least one element</B> in 478 * Var-Args Parameter {@code 'elements'} 479 * 480 * @param elements a list of elements 481 * 482 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 483 * one or more of the elements in {@code 'elements'} 484 */ 485 default boolean containsKeyOR(Object... elements) 486 { 487 ReadOnlySet<K> keys = this.keySet(); 488 for (Object elem : elements) if (keys.contains(elem)) return true; 489 return false; 490 } 491 492 /** 493 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 494 * <B STYLE='color: red;'>contains exactly one key that matches an element</B> in Var-Args 495 * Parameter {@code 'elements'} 496 * 497 * @param elements a list of elements 498 * 499 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 500 * precisely one element that is also in {@code 'elements'} 501 */ 502 default boolean containsKeyXOR(Object... elements) 503 { 504 ReadOnlySet<K> keys = this.keySet(); 505 boolean found = false; 506 507 for (Object elem : elements) 508 509 if (keys.contains(elem)) 510 { 511 if (found) return false; 512 else found = true; 513 } 514 515 return found; 516 } 517 518 519 // ******************************************************************************************** 520 // ******************************************************************************************** 521 // MAP-KEYS: contains - using java.lang.Iterable 522 // ******************************************************************************************** 523 // ******************************************************************************************** 524 525 526 /** 527 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 528 * <B STYLE='color: red;'>contains a matching key for every one of the elements</B> in 529 * {@code Iterable} parameter {@code 'i'}. 530 * 531 * @param i any Java {@code Iterable} 532 * 533 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 534 * every element in {@code 'i'} 535 */ 536 default boolean containsKeyAND(Iterable<?> i) 537 { 538 ReadOnlySet<K> keys = this.keySet(); 539 for (Object o: i) if (! keys.contains(o)) return false; 540 return true; 541 } 542 543 /** 544 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 545 * <B STYLE='color: red;'>does not contain any key that matches any of the elements</B> in 546 * {@code Iterable} parameter {@code 'i'} 547 * 548 * @param i any Java {@code Iterable} 549 * 550 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 551 * none of the elements in {@code 'i'} 552 */ 553 default boolean containsKeyNAND(Iterable<?> i) 554 { 555 ReadOnlySet<K> keys = this.keySet(); 556 for (Object o: i) if (keys.contains(o)) return false; 557 return true; 558 } 559 560 /** 561 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 562 * <B STYLE='color: red;'>contains at least one key that matches at least one element</B> in 563 * {@code Iterable} parameter {@code 'i'} 564 * 565 * @param i any Java {@code Iterable} 566 * 567 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 568 * one or more of the elements in {@code 'i'} 569 */ 570 default boolean containsKeyOR(Iterable<?> i) 571 { 572 ReadOnlySet<K> keys = this.keySet(); 573 for (Object o: i) if (keys.contains(o)) return true; 574 return false; 575 } 576 577 /** 578 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 579 * <B STYLE='color: red;'>contains exactly one key that matches an element</B> in 580 * {@code Iterable} parameter {@code 'i'} 581 * 582 * @param i any Java {@code Iterable} 583 * 584 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains 585 * precisely one element that is also in {@code 'i'} 586 */ 587 default boolean containsKeyXOR(Iterable<?> i) 588 { 589 ReadOnlySet<K> keys = this.keySet(); 590 boolean found = false; 591 592 for (Object o: i) 593 594 if (keys.contains(o)) 595 { 596 if (found) return false; 597 else found = true; 598 } 599 600 return found; 601 } 602 603 604 // ******************************************************************************************** 605 // ******************************************************************************************** 606 // MAP-VALUES: contains - using Var-Args Arrays 607 // ******************************************************************************************** 608 // ******************************************************************************************** 609 610 611 /** 612 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 613 * <B STYLE='color: red;'>contains a matching value for every one of the elements</B> in 614 * Var-Args Parameter {@code 'elements'} 615 * 616 * @param elements a list of elements 617 * 618 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 619 * every element in {@code 'elements'} 620 */ 621 default boolean containsValueAND(Object... elements) 622 { 623 ReadOnlyCollection<V> values = this.values(); 624 for (Object elem : elements) if (! values.contains(elem)) return false; 625 return true; 626 } 627 628 /** 629 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 630 * <B STYLE='color: red;'>does not contain any value that matches any of the elements</B> in 631 * Var-Args Parameter {@code 'elements'} 632 * 633 * @param elements a list of elements 634 * 635 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 636 * none of the elements in {@code 'elements'} 637 */ 638 default boolean containsValueNAND(Object... elements) 639 { 640 ReadOnlyCollection<V> values = this.values(); 641 for (Object elem : elements) if (values.contains(elem)) return false; 642 return true; 643 } 644 645 /** 646 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 647 * <B STYLE='color: red;'>contains at least one value that matches at least one element</B> in 648 * Var-Args Parameter {@code 'elements'} 649 * 650 * @param elements a list of elements 651 * 652 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 653 * one or more of the elements in {@code 'elements'} 654 */ 655 default boolean containsValueOR(Object... elements) 656 { 657 ReadOnlyCollection<V> values = this.values(); 658 for (Object elem : elements) if (values.contains(elem)) return true; 659 return false; 660 } 661 662 /** 663 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 664 * <B STYLE='color: red;'>contains exactly one value that matches an element</B> in Var-Args 665 * Parameter {@code 'elements'} 666 * 667 * @param elements a list of elements 668 * 669 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 670 * precisely one element that is also in {@code 'elements'} 671 */ 672 default boolean containsValueXOR(Object... elements) 673 { 674 ReadOnlyCollection<V> values = this.values(); 675 boolean found = false; 676 677 for (Object elem : elements) 678 679 if (values.contains(elem)) 680 { 681 if (found) return false; 682 else found = true; 683 } 684 685 return found; 686 } 687 688 689 // ******************************************************************************************** 690 // ******************************************************************************************** 691 // MAP-VALUES: contains - using java.lang.Iterable 692 // ******************************************************************************************** 693 // ******************************************************************************************** 694 695 696 /** 697 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 698 * <B STYLE='color: red;'>contains a matching value for every one of the elements</B> in 699 * {@code Iterable} parameter {@code 'i'} 700 * 701 * @param i any Java {@code Iterable} 702 * 703 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 704 * every element in {@code 'i'} 705 */ 706 default boolean containsValueAND(Iterable<?> i) 707 { 708 ReadOnlyCollection<V> values = this.values(); 709 for (Object o: i) if (! values.contains(o)) return false; 710 return true; 711 } 712 713 /** 714 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 715 * <B STYLE='color: red;'>does not contain any value that matches any of the elements</B> in 716 * {@code Iterable} parameter {@code 'i'} 717 * 718 * @param i any Java {@code Iterable} 719 * 720 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 721 * none of the elements in {@code 'i'} 722 */ 723 default boolean containsValueNAND(Iterable<?> i) 724 { 725 ReadOnlyCollection<V> values = this.values(); 726 for (Object o: i) if (values.contains(o)) return false; 727 return true; 728 } 729 730 /** 731 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 732 * <B STYLE='color: red;'>contains at least one value that matches at least one element</B> in 733 * {@code Iterable} parameter {@code 'i'} 734 * 735 * @param i any Java {@code Iterable} 736 * 737 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 738 * one or more of the elements in {@code 'i'} 739 */ 740 default boolean containsValueOR(Iterable<?> i) 741 { 742 ReadOnlyCollection<V> values = this.values(); 743 for (Object o: i) if (values.contains(o)) return true; 744 return false; 745 } 746 747 /** 748 * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap} 749 * <B STYLE='color: red;'>contains exactly one value that matches an element</B> in 750 * {@code Iterable} parameter {@code 'i'} 751 * 752 * @param i any Java {@code Iterable} 753 * 754 * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains 755 * precisely one element that is also in {@code 'i'} 756 */ 757 default boolean containsValueXOR(Iterable<?> i) 758 { 759 ReadOnlyCollection<V> values = this.values(); 760 boolean found = false; 761 762 for (Object o: i) 763 764 if (values.contains(o)) 765 { 766 if (found) return false; 767 else found = true; 768 } 769 770 return found; 771 } 772 773 774 // ******************************************************************************************** 775 // ******************************************************************************************** 776 // "of" ... 777 // ******************************************************************************************** 778 // ******************************************************************************************** 779 780 781 /** 782 * Returns an unmodifiable map containing zero mappings. 783 * 784 * @param <K> the {@code Map}'s key type 785 * @param <V> the {@code Map}'s value type 786 * @return an empty {@code Map} 787 */ 788 @SuppressWarnings("unchecked") 789 static <K, V> ReadOnlyMap<K, V> of() 790 { return InterfaceBuilder.toReadOnlyMap(Map.of()); } 791 792 /** 793 * Returns an unmodifiable map containing a single mapping. 794 * 795 * @param <K> the {@code Map}'s key type 796 * @param <V> the {@code Map}'s value type 797 * @param k1 the mapping's key 798 * @param v1 the mapping's value 799 * 800 * @return a {@link ReadOnlyMap} containing the specified mapping 801 * @throws NullPointerException if the key or the value is {@code null} 802 */ 803 static <K, V> ReadOnlyMap<K, V> of(K k1, V v1) 804 { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1)); } 805 806 /** 807 * Returns an unmodifiable map containing two mappings. 808 * 809 * @param <K> the {@code Map}'s key type 810 * @param <V> the {@code Map}'s value type 811 * @param k1 the first mapping's key 812 * @param v1 the first mapping's value 813 * @param k2 the second mapping's key 814 * @param v2 the second mapping's value 815 * 816 * @return a {@link ReadOnlyMap} containing the specified mappings 817 * @throws IllegalArgumentException if the keys are duplicates 818 * @throws NullPointerException if any key or value is {@code null} 819 */ 820 static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2) 821 { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2)); } 822 823 /** 824 * Returns an unmodifiable map containing three mappings. 825 * 826 * @param <K> the {@code Map}'s key type 827 * @param <V> the {@code Map}'s value type 828 * @param k1 the first mapping's key 829 * @param v1 the first mapping's value 830 * @param k2 the second mapping's key 831 * @param v2 the second mapping's value 832 * @param k3 the third mapping's key 833 * @param v3 the third mapping's value 834 * 835 * @return a {@link ReadOnlyMap} containing the specified mappings 836 * @throws IllegalArgumentException if there are any duplicate keys 837 * @throws NullPointerException if any key or value is {@code null} 838 */ 839 static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) 840 { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2, k3, v3)); } 841 842 /** 843 * Returns an unmodifiable map containing four mappings. 844 * 845 * @param <K> the {@code Map}'s key type 846 * @param <V> the {@code Map}'s value type 847 * @param k1 the first mapping's key 848 * @param v1 the first mapping's value 849 * @param k2 the second mapping's key 850 * @param v2 the second mapping's value 851 * @param k3 the third mapping's key 852 * @param v3 the third mapping's value 853 * @param k4 the fourth mapping's key 854 * @param v4 the fourth mapping's value 855 * 856 * @return a {@link ReadOnlyMap} containing the specified mappings 857 * @throws IllegalArgumentException if there are any duplicate keys 858 * @throws NullPointerException if any key or value is {@code null} 859 */ 860 static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) 861 { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2, k3, v3, k4, v4)); } 862 863 /** 864 * Returns an unmodifiable map containing five mappings. 865 * 866 * @param <K> the {@code Map}'s key type 867 * @param <V> the {@code Map}'s value type 868 * @param k1 the first mapping's key 869 * @param v1 the first mapping's value 870 * @param k2 the second mapping's key 871 * @param v2 the second mapping's value 872 * @param k3 the third mapping's key 873 * @param v3 the third mapping's value 874 * @param k4 the fourth mapping's key 875 * @param v4 the fourth mapping's value 876 * @param k5 the fifth mapping's key 877 * @param v5 the fifth mapping's value 878 * 879 * @return a {@link ReadOnlyMap} containing the specified mappings 880 * @throws IllegalArgumentException if there are any duplicate keys 881 * @throws NullPointerException if any key or value is {@code null} 882 * 883 */ 884 static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) 885 { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5)); } 886 887 /** 888 * Returns an unmodifiable map containing six mappings. 889 * 890 * @param <K> the {@code Map}'s key type 891 * @param <V> the {@code Map}'s value type 892 * @param k1 the first mapping's key 893 * @param v1 the first mapping's value 894 * @param k2 the second mapping's key 895 * @param v2 the second mapping's value 896 * @param k3 the third mapping's key 897 * @param v3 the third mapping's value 898 * @param k4 the fourth mapping's key 899 * @param v4 the fourth mapping's value 900 * @param k5 the fifth mapping's key 901 * @param v5 the fifth mapping's value 902 * @param k6 the sixth mapping's key 903 * @param v6 the sixth mapping's value 904 * 905 * @return a {@link ReadOnlyMap} containing the specified mappings 906 * @throws IllegalArgumentException if there are any duplicate keys 907 * @throws NullPointerException if any key or value is {@code null} 908 */ 909 static <K, V> ReadOnlyMap<K, V> of( 910 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, 911 K k6, V v6 912 ) 913 { 914 return InterfaceBuilder.toReadOnlyMap 915 (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6)); 916 } 917 918 /** 919 * Returns an unmodifiable map containing seven mappings. 920 * 921 * @param <K> the {@code Map}'s key type 922 * @param <V> the {@code Map}'s value type 923 * @param k1 the first mapping's key 924 * @param v1 the first mapping's value 925 * @param k2 the second mapping's key 926 * @param v2 the second mapping's value 927 * @param k3 the third mapping's key 928 * @param v3 the third mapping's value 929 * @param k4 the fourth mapping's key 930 * @param v4 the fourth mapping's value 931 * @param k5 the fifth mapping's key 932 * @param v5 the fifth mapping's value 933 * @param k6 the sixth mapping's key 934 * @param v6 the sixth mapping's value 935 * @param k7 the seventh mapping's key 936 * @param v7 the seventh mapping's value 937 * 938 * @return a {@link ReadOnlyMap} containing the specified mappings 939 * @throws IllegalArgumentException if there are any duplicate keys 940 * @throws NullPointerException if any key or value is {@code null} 941 */ 942 static <K, V> ReadOnlyMap<K, V> of( 943 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, 944 K k6, V v6, K k7, V v7 945 ) 946 { 947 return InterfaceBuilder.toReadOnlyMap 948 (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7)); 949 } 950 951 /** 952 * Returns an unmodifiable map containing eight mappings. 953 * 954 * @param <K> the {@code Map}'s key type 955 * @param <V> the {@code Map}'s value type 956 * @param k1 the first mapping's key 957 * @param v1 the first mapping's value 958 * @param k2 the second mapping's key 959 * @param v2 the second mapping's value 960 * @param k3 the third mapping's key 961 * @param v3 the third mapping's value 962 * @param k4 the fourth mapping's key 963 * @param v4 the fourth mapping's value 964 * @param k5 the fifth mapping's key 965 * @param v5 the fifth mapping's value 966 * @param k6 the sixth mapping's key 967 * @param v6 the sixth mapping's value 968 * @param k7 the seventh mapping's key 969 * @param v7 the seventh mapping's value 970 * @param k8 the eighth mapping's key 971 * @param v8 the eighth mapping's value 972 * 973 * @return a {@link ReadOnlyMap} containing the specified mappings 974 * @throws IllegalArgumentException if there are any duplicate keys 975 * @throws NullPointerException if any key or value is {@code null} 976 */ 977 static <K, V> ReadOnlyMap<K, V> of( 978 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, 979 K k6, V v6, K k7, V v7, K k8, V v8 980 ) 981 { 982 return InterfaceBuilder.toReadOnlyMap 983 (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8)); 984 } 985 986 /** 987 * Returns an unmodifiable map containing nine mappings. 988 * 989 * @param <K> the {@code Map}'s key type 990 * @param <V> the {@code Map}'s value type 991 * @param k1 the first mapping's key 992 * @param v1 the first mapping's value 993 * @param k2 the second mapping's key 994 * @param v2 the second mapping's value 995 * @param k3 the third mapping's key 996 * @param v3 the third mapping's value 997 * @param k4 the fourth mapping's key 998 * @param v4 the fourth mapping's value 999 * @param k5 the fifth mapping's key 1000 * @param v5 the fifth mapping's value 1001 * @param k6 the sixth mapping's key 1002 * @param v6 the sixth mapping's value 1003 * @param k7 the seventh mapping's key 1004 * @param v7 the seventh mapping's value 1005 * @param k8 the eighth mapping's key 1006 * @param v8 the eighth mapping's value 1007 * @param k9 the ninth mapping's key 1008 * @param v9 the ninth mapping's value 1009 * 1010 * @return a {@link ReadOnlyMap} containing the specified mappings 1011 * @throws IllegalArgumentException if there are any duplicate keys 1012 * @throws NullPointerException if any key or value is {@code null} 1013 */ 1014 static <K, V> ReadOnlyMap<K, V> of( 1015 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, 1016 K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9 1017 ) 1018 { 1019 return InterfaceBuilder.toReadOnlyMap 1020 (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9)); 1021 } 1022 1023 /** 1024 * Returns an unmodifiable map containing ten mappings. 1025 * 1026 * @param <K> the {@code Map}'s key type 1027 * @param <V> the {@code Map}'s value type 1028 * @param k1 the first mapping's key 1029 * @param v1 the first mapping's value 1030 * @param k2 the second mapping's key 1031 * @param v2 the second mapping's value 1032 * @param k3 the third mapping's key 1033 * @param v3 the third mapping's value 1034 * @param k4 the fourth mapping's key 1035 * @param v4 the fourth mapping's value 1036 * @param k5 the fifth mapping's key 1037 * @param v5 the fifth mapping's value 1038 * @param k6 the sixth mapping's key 1039 * @param v6 the sixth mapping's value 1040 * @param k7 the seventh mapping's key 1041 * @param v7 the seventh mapping's value 1042 * @param k8 the eighth mapping's key 1043 * @param v8 the eighth mapping's value 1044 * @param k9 the ninth mapping's key 1045 * @param v9 the ninth mapping's value 1046 * @param k10 the tenth mapping's key 1047 * @param v10 the tenth mapping's value 1048 * 1049 * @return a {@link ReadOnlyMap} containing the specified mappings 1050 * @throws IllegalArgumentException if there are any duplicate keys 1051 * @throws NullPointerException if any key or value is {@code null} 1052 */ 1053 static <K, V> ReadOnlyMap<K, V> of( 1054 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, 1055 K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10 1056 ) 1057 { 1058 return InterfaceBuilder.toReadOnlyMap( 1059 Map.of( 1060 k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, 1061 k7, v7, k8, v8, k9, v9, k10, v10 1062 )); 1063 } 1064 1065 /** 1066 * Returns an unmodifiable map containing keys and values extracted from the given entries. 1067 * The entries themselves are not stored in the map. 1068 * 1069 * <BR /><BR />It is convenient to create the map entries using the 1070 * {@link ReadOnlyMap#entry ReadOnlyMap.entry()} method. For example, 1071 * 1072 * <DIV CLASS=EXAMPLE>{@code 1073 * import static Torello.Java.ReadOnly.ReadOnlyMap.entry; 1074 * 1075 * ReadOnlyMap<Integer,String> map = ReadOnlyMap.ofEntries( 1076 * entry(1, "a"), 1077 * entry(2, "b"), 1078 * entry(3, "c"), 1079 * ... 1080 * entry(26, "z")); 1081 * }</DIV> 1082 * 1083 * @param <K> the {@link ReadOnlyMap}'s key type 1084 * @param <V> the {@link ReadOnlyMap}'s value type 1085 * 1086 * @param entries {@code ReadOnlyMap.Entry}s containing the keys and values from which the map 1087 * is populated 1088 * 1089 * @return a {@link ReadOnlyMap} containing the specified mappings 1090 * @throws IllegalArgumentException if there are any duplicate keys 1091 * 1092 * @throws NullPointerException if any entry, key, or value is {@code null}, or if the 1093 * {@code entries} array is {@code null} 1094 * 1095 * @see ReadOnlyMap#entry Map.entry() 1096 */ 1097 @SafeVarargs 1098 @SuppressWarnings("varargs") 1099 static <K, V> 1100 ReadOnlyMap<K, V> 1101 ofEntries 1102 (ReadOnlyMap.Entry<? extends K, ? extends V>... entries) 1103 { 1104 // *** Java-HTML: This arbitrarily uses TreeMap 1105 ROTreeMapBuilder<K, V> b = new ROTreeMapBuilder<>(); 1106 1107 for (ReadOnlyMap.Entry<? extends K, ? extends V> e : entries) 1108 b.put(e.getKey(), e.getValue()); 1109 1110 return b.build(); 1111 } 1112 1113 /** 1114 * Returns an unmodifiable {@link Entry} containing the given key and value. 1115 * These entries are suitable for populating {@code ReadOnlyMap} instances using the 1116 * {@link ReadOnlyMap#ofEntries ReadOnlyMap.ofEntries()} method. 1117 * 1118 * @param <K> the key's type 1119 * @param <V> the value's type 1120 * @param k the key 1121 * @param v the value 1122 * @return an {@code Entry} containing the specified key and value 1123 * @throws NullPointerException if the key or value is {@code null} 1124 * 1125 * @see ReadOnlyMap#ofEntries Map.ofEntries() 1126 */ 1127 static <K, V> ReadOnlyMap.Entry<K, V> entry(K k, V v) 1128 { 1129 // KeyValueHolder checks for nulls 1130 // return new KeyValueHolder<>(k, v); 1131 return new EntryImpl<>(Objects.requireNonNull(k), Objects.requireNonNull(v)); 1132 } 1133}