001/* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import static com.google.common.base.Preconditions.checkNotNull; 020import static com.google.common.base.Preconditions.checkState; 021import static com.google.common.collect.CollectPreconditions.checkEntryNotNull; 022import static com.google.common.collect.CollectPreconditions.checkNonnegative; 023 024import com.google.common.annotations.Beta; 025import com.google.common.annotations.GwtCompatible; 026import com.google.errorprone.annotations.CanIgnoreReturnValue; 027import com.google.errorprone.annotations.concurrent.LazyInit; 028import com.google.j2objc.annotations.WeakOuter; 029import java.io.Serializable; 030import java.util.AbstractMap; 031import java.util.Arrays; 032import java.util.Collection; 033import java.util.Collections; 034import java.util.Comparator; 035import java.util.EnumMap; 036import java.util.Iterator; 037import java.util.LinkedHashMap; 038import java.util.Map; 039import java.util.Map.Entry; 040import java.util.SortedMap; 041import java.util.Spliterator; 042import java.util.Spliterators; 043import java.util.function.BiFunction; 044import java.util.function.BinaryOperator; 045import java.util.function.Function; 046import java.util.stream.Collector; 047import java.util.stream.Collectors; 048import org.checkerframework.checker.nullness.compatqual.MonotonicNonNullDecl; 049import org.checkerframework.checker.nullness.compatqual.NullableDecl; 050 051/** 052 * A {@link Map} whose contents will never change, with many other important properties detailed at 053 * {@link ImmutableCollection}. 054 * 055 * <p>See the Guava User Guide article on <a href= 056 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>. 057 * 058 * @author Jesse Wilson 059 * @author Kevin Bourrillion 060 * @since 2.0 061 */ 062@GwtCompatible(serializable = true, emulated = true) 063@SuppressWarnings("serial") // we're overriding default serialization 064public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable { 065 066 /** 067 * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys 068 * and values are the result of applying the provided mapping functions to the input elements. 069 * Entries appear in the result {@code ImmutableMap} in encounter order. 070 * 071 * <p>If the mapped keys contain duplicates (according to {@link Object#equals(Object)}, an {@code 072 * IllegalArgumentException} is thrown when the collection operation is performed. (This differs 073 * from the {@code Collector} returned by {@link Collectors#toMap(Function, Function)}, which 074 * throws an {@code IllegalStateException}.) 075 * 076 * @since 21.0 077 */ 078 @Beta 079 public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap( 080 Function<? super T, ? extends K> keyFunction, 081 Function<? super T, ? extends V> valueFunction) { 082 return CollectCollectors.toImmutableMap(keyFunction, valueFunction); 083 } 084 085 /** 086 * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys 087 * and values are the result of applying the provided mapping functions to the input elements. 088 * 089 * <p>If the mapped keys contain duplicates (according to {@link Object#equals(Object)}), the 090 * values are merged using the specified merging function. Entries will appear in the encounter 091 * order of the first occurrence of the key. 092 * 093 * @since 21.0 094 */ 095 @Beta 096 public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap( 097 Function<? super T, ? extends K> keyFunction, 098 Function<? super T, ? extends V> valueFunction, 099 BinaryOperator<V> mergeFunction) { 100 checkNotNull(keyFunction); 101 checkNotNull(valueFunction); 102 checkNotNull(mergeFunction); 103 return Collectors.collectingAndThen( 104 Collectors.toMap(keyFunction, valueFunction, mergeFunction, LinkedHashMap::new), 105 ImmutableMap::copyOf); 106 } 107 108 /** 109 * Returns the empty map. This map behaves and performs comparably to {@link 110 * Collections#emptyMap}, and is preferable mainly for consistency and maintainability of your 111 * code. 112 */ 113 @SuppressWarnings("unchecked") 114 public static <K, V> ImmutableMap<K, V> of() { 115 return (ImmutableMap<K, V>) RegularImmutableMap.EMPTY; 116 } 117 118 /** 119 * Returns an immutable map containing a single entry. This map behaves and performs comparably to 120 * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable 121 * mainly for consistency and maintainability of your code. 122 */ 123 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) { 124 return ImmutableBiMap.of(k1, v1); 125 } 126 127 /** 128 * Returns an immutable map containing the given entries, in order. 129 * 130 * @throws IllegalArgumentException if duplicate keys are provided 131 */ 132 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) { 133 return RegularImmutableMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2)); 134 } 135 136 /** 137 * Returns an immutable map containing the given entries, in order. 138 * 139 * @throws IllegalArgumentException if duplicate keys are provided 140 */ 141 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 142 return RegularImmutableMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); 143 } 144 145 /** 146 * Returns an immutable map containing the given entries, in order. 147 * 148 * @throws IllegalArgumentException if duplicate keys are provided 149 */ 150 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 151 return RegularImmutableMap.fromEntries( 152 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); 153 } 154 155 /** 156 * Returns an immutable map containing the given entries, in order. 157 * 158 * @throws IllegalArgumentException if duplicate keys are provided 159 */ 160 public static <K, V> ImmutableMap<K, V> of( 161 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 162 return RegularImmutableMap.fromEntries( 163 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); 164 } 165 166 // looking for of() with > 5 entries? Use the builder instead. 167 168 /** 169 * Verifies that {@code key} and {@code value} are non-null, and returns a new immutable entry 170 * with those values. 171 * 172 * <p>A call to {@link Entry#setValue} on the returned entry will always throw {@link 173 * UnsupportedOperationException}. 174 */ 175 static <K, V> Entry<K, V> entryOf(K key, V value) { 176 checkEntryNotNull(key, value); 177 return new AbstractMap.SimpleImmutableEntry<>(key, value); 178 } 179 180 /** 181 * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 182 * Builder} constructor. 183 */ 184 public static <K, V> Builder<K, V> builder() { 185 return new Builder<>(); 186 } 187 188 /** 189 * Returns a new builder, expecting the specified number of entries to be added. 190 * 191 * <p>If {@code expectedSize} is exactly the number of entries added to the builder before {@link 192 * Builder#build} is called, the builder is likely to perform better than an unsized {@link 193 * #builder()} would have. 194 * 195 * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to, 196 * but not exactly, the number of entries added to the builder. 197 * 198 * @since 23.1 199 */ 200 @Beta 201 public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) { 202 checkNonnegative(expectedSize, "expectedSize"); 203 return new Builder<>(expectedSize); 204 } 205 206 static void checkNoConflict( 207 boolean safe, String conflictDescription, Entry<?, ?> entry1, Entry<?, ?> entry2) { 208 if (!safe) { 209 throw new IllegalArgumentException( 210 "Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2); 211 } 212 } 213 214 /** 215 * A builder for creating immutable map instances, especially {@code public static final} maps 216 * ("constant maps"). Example: 217 * 218 * <pre>{@code 219 * static final ImmutableMap<String, Integer> WORD_TO_INT = 220 * new ImmutableMap.Builder<String, Integer>() 221 * .put("one", 1) 222 * .put("two", 2) 223 * .put("three", 3) 224 * .build(); 225 * }</pre> 226 * 227 * <p>For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are even more 228 * convenient. 229 * 230 * <p>By default, a {@code Builder} will generate maps that iterate over entries in the order they 231 * were inserted into the builder, equivalently to {@code LinkedHashMap}. For example, in the 232 * above example, {@code WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the 233 * order {@code "one"=1, "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect 234 * the same order. If you want a different order, consider using {@link ImmutableSortedMap} to 235 * sort by keys, or call {@link #orderEntriesByValue(Comparator)}, which changes this builder to 236 * sort entries by value. 237 * 238 * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build 239 * multiple maps in series. Each map is a superset of the maps created before it. 240 * 241 * @since 2.0 242 */ 243 public static class Builder<K, V> { 244 @MonotonicNonNullDecl Comparator<? super V> valueComparator; 245 Entry<K, V>[] entries; 246 int size; 247 boolean entriesUsed; 248 249 /** 250 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 251 * ImmutableMap#builder}. 252 */ 253 public Builder() { 254 this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY); 255 } 256 257 @SuppressWarnings("unchecked") 258 Builder(int initialCapacity) { 259 this.entries = new Entry[initialCapacity]; 260 this.size = 0; 261 this.entriesUsed = false; 262 } 263 264 private void ensureCapacity(int minCapacity) { 265 if (minCapacity > entries.length) { 266 entries = 267 Arrays.copyOf( 268 entries, ImmutableCollection.Builder.expandedCapacity(entries.length, minCapacity)); 269 entriesUsed = false; 270 } 271 } 272 273 /** 274 * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed, 275 * and will cause {@link #build} to fail. 276 */ 277 @CanIgnoreReturnValue 278 public Builder<K, V> put(K key, V value) { 279 ensureCapacity(size + 1); 280 Entry<K, V> entry = entryOf(key, value); 281 // don't inline this: we want to fail atomically if key or value is null 282 entries[size++] = entry; 283 return this; 284 } 285 286 /** 287 * Adds the given {@code entry} to the map, making it immutable if necessary. Duplicate keys are 288 * not allowed, and will cause {@link #build} to fail. 289 * 290 * @since 11.0 291 */ 292 @CanIgnoreReturnValue 293 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 294 return put(entry.getKey(), entry.getValue()); 295 } 296 297 /** 298 * Associates all of the given map's keys and values in the built map. Duplicate keys are not 299 * allowed, and will cause {@link #build} to fail. 300 * 301 * @throws NullPointerException if any key or value in {@code map} is null 302 */ 303 @CanIgnoreReturnValue 304 public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 305 return putAll(map.entrySet()); 306 } 307 308 /** 309 * Adds all of the given entries to the built map. Duplicate keys are not allowed, and will 310 * cause {@link #build} to fail. 311 * 312 * @throws NullPointerException if any key, value, or entry is null 313 * @since 19.0 314 */ 315 @CanIgnoreReturnValue 316 @Beta 317 public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) { 318 if (entries instanceof Collection) { 319 ensureCapacity(size + ((Collection<?>) entries).size()); 320 } 321 for (Entry<? extends K, ? extends V> entry : entries) { 322 put(entry); 323 } 324 return this; 325 } 326 327 /** 328 * Configures this {@code Builder} to order entries by value according to the specified 329 * comparator. 330 * 331 * <p>The sort order is stable, that is, if two entries have values that compare as equivalent, 332 * the entry that was inserted first will be first in the built map's iteration order. 333 * 334 * @throws IllegalStateException if this method was already called 335 * @since 19.0 336 */ 337 @CanIgnoreReturnValue 338 @Beta 339 public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) { 340 checkState(this.valueComparator == null, "valueComparator was already set"); 341 this.valueComparator = checkNotNull(valueComparator, "valueComparator"); 342 return this; 343 } 344 345 @CanIgnoreReturnValue 346 Builder<K, V> combine(Builder<K, V> other) { 347 checkNotNull(other); 348 ensureCapacity(this.size + other.size); 349 System.arraycopy(other.entries, 0, this.entries, this.size, other.size); 350 this.size += other.size; 351 return this; 352 } 353 354 /* 355 * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap 356 * versions throw an IllegalStateException instead? 357 */ 358 359 /** 360 * Returns a newly-created immutable map. The iteration order of the returned map is the order 361 * in which entries were inserted into the builder, unless {@link #orderEntriesByValue} was 362 * called, in which case entries are sorted by value. 363 * 364 * @throws IllegalArgumentException if duplicate keys were added 365 */ 366 public ImmutableMap<K, V> build() { 367 /* 368 * If entries is full, then this implementation may end up using the entries array 369 * directly and writing over the entry objects with non-terminal entries, but this is 370 * safe; if this Builder is used further, it will grow the entries array (so it can't 371 * affect the original array), and future build() calls will always copy any entry 372 * objects that cannot be safely reused. 373 */ 374 if (valueComparator != null) { 375 if (entriesUsed) { 376 entries = Arrays.copyOf(entries, size); 377 } 378 Arrays.sort( 379 entries, 0, size, Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction())); 380 } 381 entriesUsed = size == entries.length; 382 switch (size) { 383 case 0: 384 return of(); 385 case 1: 386 return of(entries[0].getKey(), entries[0].getValue()); 387 default: 388 return RegularImmutableMap.fromEntryArray(size, entries); 389 } 390 } 391 } 392 393 /** 394 * Returns an immutable map containing the same entries as {@code map}. The returned map iterates 395 * over entries in the same order as the {@code entrySet} of the original map. If {@code map} 396 * somehow contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose 397 * comparator is not <i>consistent with equals</i>), the results of this method are undefined. 398 * 399 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 400 * safe to do so. The exact circumstances under which a copy will or will not be performed are 401 * undocumented and subject to change. 402 * 403 * @throws NullPointerException if any key or value in {@code map} is null 404 */ 405 public static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V> map) { 406 if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) { 407 @SuppressWarnings("unchecked") // safe since map is not writable 408 ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map; 409 if (!kvMap.isPartialView()) { 410 return kvMap; 411 } 412 } else if (map instanceof EnumMap) { 413 @SuppressWarnings("unchecked") // safe since map is not writable 414 ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) copyOfEnumMap((EnumMap<?, ?>) map); 415 return kvMap; 416 } 417 return copyOf(map.entrySet()); 418 } 419 420 /** 421 * Returns an immutable map containing the specified entries. The returned map iterates over 422 * entries in the same order as the original iterable. 423 * 424 * @throws NullPointerException if any key, value, or entry is null 425 * @throws IllegalArgumentException if two entries have the same key 426 * @since 19.0 427 */ 428 @Beta 429 public static <K, V> ImmutableMap<K, V> copyOf( 430 Iterable<? extends Entry<? extends K, ? extends V>> entries) { 431 @SuppressWarnings("unchecked") // we'll only be using getKey and getValue, which are covariant 432 Entry<K, V>[] entryArray = (Entry<K, V>[]) Iterables.toArray(entries, EMPTY_ENTRY_ARRAY); 433 switch (entryArray.length) { 434 case 0: 435 return of(); 436 case 1: 437 Entry<K, V> onlyEntry = entryArray[0]; 438 return of(onlyEntry.getKey(), onlyEntry.getValue()); 439 default: 440 /* 441 * The current implementation will end up using entryArray directly, though it will write 442 * over the (arbitrary, potentially mutable) Entry objects actually stored in entryArray. 443 */ 444 return RegularImmutableMap.fromEntries(entryArray); 445 } 446 } 447 448 private static <K extends Enum<K>, V> ImmutableMap<K, V> copyOfEnumMap( 449 EnumMap<K, ? extends V> original) { 450 EnumMap<K, V> copy = new EnumMap<>(original); 451 for (Entry<?, ?> entry : copy.entrySet()) { 452 checkEntryNotNull(entry.getKey(), entry.getValue()); 453 } 454 return ImmutableEnumMap.asImmutable(copy); 455 } 456 457 static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0]; 458 459 abstract static class IteratorBasedImmutableMap<K, V> extends ImmutableMap<K, V> { 460 abstract UnmodifiableIterator<Entry<K, V>> entryIterator(); 461 462 Spliterator<Entry<K, V>> entrySpliterator() { 463 return Spliterators.spliterator( 464 entryIterator(), 465 size(), 466 Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.IMMUTABLE | Spliterator.ORDERED); 467 } 468 469 @Override 470 ImmutableSet<K> createKeySet() { 471 return new ImmutableMapKeySet<>(this); 472 } 473 474 @Override 475 ImmutableSet<Entry<K, V>> createEntrySet() { 476 @WeakOuter 477 class EntrySetImpl extends ImmutableMapEntrySet<K, V> { 478 @Override 479 ImmutableMap<K, V> map() { 480 return IteratorBasedImmutableMap.this; 481 } 482 483 @Override 484 public UnmodifiableIterator<Entry<K, V>> iterator() { 485 return entryIterator(); 486 } 487 } 488 return new EntrySetImpl(); 489 } 490 491 @Override 492 ImmutableCollection<V> createValues() { 493 return new ImmutableMapValues<>(this); 494 } 495 } 496 497 ImmutableMap() {} 498 499 /** 500 * Guaranteed to throw an exception and leave the map unmodified. 501 * 502 * @throws UnsupportedOperationException always 503 * @deprecated Unsupported operation. 504 */ 505 @CanIgnoreReturnValue 506 @Deprecated 507 @Override 508 public final V put(K k, V v) { 509 throw new UnsupportedOperationException(); 510 } 511 512 /** 513 * Guaranteed to throw an exception and leave the map unmodified. 514 * 515 * @throws UnsupportedOperationException always 516 * @deprecated Unsupported operation. 517 */ 518 @CanIgnoreReturnValue 519 @Deprecated 520 @Override 521 public final V putIfAbsent(K key, V value) { 522 throw new UnsupportedOperationException(); 523 } 524 525 /** 526 * Guaranteed to throw an exception and leave the map unmodified. 527 * 528 * @throws UnsupportedOperationException always 529 * @deprecated Unsupported operation. 530 */ 531 @Deprecated 532 @Override 533 public final boolean replace(K key, V oldValue, V newValue) { 534 throw new UnsupportedOperationException(); 535 } 536 537 /** 538 * Guaranteed to throw an exception and leave the map unmodified. 539 * 540 * @throws UnsupportedOperationException always 541 * @deprecated Unsupported operation. 542 */ 543 @Deprecated 544 @Override 545 public final V replace(K key, V value) { 546 throw new UnsupportedOperationException(); 547 } 548 549 /** 550 * Guaranteed to throw an exception and leave the map unmodified. 551 * 552 * @throws UnsupportedOperationException always 553 * @deprecated Unsupported operation. 554 */ 555 @Deprecated 556 @Override 557 public final V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { 558 throw new UnsupportedOperationException(); 559 } 560 561 /** 562 * Guaranteed to throw an exception and leave the map unmodified. 563 * 564 * @throws UnsupportedOperationException always 565 * @deprecated Unsupported operation. 566 */ 567 @Deprecated 568 @Override 569 public final V computeIfPresent( 570 K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 571 throw new UnsupportedOperationException(); 572 } 573 574 /** 575 * Guaranteed to throw an exception and leave the map unmodified. 576 * 577 * @throws UnsupportedOperationException always 578 * @deprecated Unsupported operation. 579 */ 580 @Deprecated 581 @Override 582 public final V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 583 throw new UnsupportedOperationException(); 584 } 585 586 /** 587 * Guaranteed to throw an exception and leave the map unmodified. 588 * 589 * @throws UnsupportedOperationException always 590 * @deprecated Unsupported operation. 591 */ 592 @Deprecated 593 @Override 594 public final V merge( 595 K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { 596 throw new UnsupportedOperationException(); 597 } 598 599 /** 600 * Guaranteed to throw an exception and leave the map unmodified. 601 * 602 * @throws UnsupportedOperationException always 603 * @deprecated Unsupported operation. 604 */ 605 @Deprecated 606 @Override 607 public final void putAll(Map<? extends K, ? extends V> map) { 608 throw new UnsupportedOperationException(); 609 } 610 611 /** 612 * Guaranteed to throw an exception and leave the map unmodified. 613 * 614 * @throws UnsupportedOperationException always 615 * @deprecated Unsupported operation. 616 */ 617 @Deprecated 618 @Override 619 public final void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { 620 throw new UnsupportedOperationException(); 621 } 622 623 /** 624 * Guaranteed to throw an exception and leave the map unmodified. 625 * 626 * @throws UnsupportedOperationException always 627 * @deprecated Unsupported operation. 628 */ 629 @Deprecated 630 @Override 631 public final V remove(Object o) { 632 throw new UnsupportedOperationException(); 633 } 634 635 /** 636 * Guaranteed to throw an exception and leave the map unmodified. 637 * 638 * @throws UnsupportedOperationException always 639 * @deprecated Unsupported operation. 640 */ 641 @Deprecated 642 @Override 643 public final boolean remove(Object key, Object value) { 644 throw new UnsupportedOperationException(); 645 } 646 647 /** 648 * Guaranteed to throw an exception and leave the map unmodified. 649 * 650 * @throws UnsupportedOperationException always 651 * @deprecated Unsupported operation. 652 */ 653 @Deprecated 654 @Override 655 public final void clear() { 656 throw new UnsupportedOperationException(); 657 } 658 659 @Override 660 public boolean isEmpty() { 661 return size() == 0; 662 } 663 664 @Override 665 public boolean containsKey(@NullableDecl Object key) { 666 return get(key) != null; 667 } 668 669 @Override 670 public boolean containsValue(@NullableDecl Object value) { 671 return values().contains(value); 672 } 673 674 // Overriding to mark it Nullable 675 @Override 676 public abstract V get(@NullableDecl Object key); 677 678 /** 679 * @since 21.0 (but only since 23.5 in the Android <a 680 * href="https://github.com/google/guava#guava-google-core-libraries-for-java">flavor</a>). 681 * Note, however, that Java 8 users can call this method with any version and flavor of Guava. 682 */ 683 @Override 684 public final V getOrDefault(@NullableDecl Object key, @NullableDecl V defaultValue) { 685 V result = get(key); 686 return (result != null) ? result : defaultValue; 687 } 688 689 @LazyInit private transient ImmutableSet<Entry<K, V>> entrySet; 690 691 /** 692 * Returns an immutable set of the mappings in this map. The iteration order is specified by the 693 * method used to create this map. Typically, this is insertion order. 694 */ 695 @Override 696 public ImmutableSet<Entry<K, V>> entrySet() { 697 ImmutableSet<Entry<K, V>> result = entrySet; 698 return (result == null) ? entrySet = createEntrySet() : result; 699 } 700 701 abstract ImmutableSet<Entry<K, V>> createEntrySet(); 702 703 @LazyInit private transient ImmutableSet<K> keySet; 704 705 /** 706 * Returns an immutable set of the keys in this map, in the same order that they appear in {@link 707 * #entrySet}. 708 */ 709 @Override 710 public ImmutableSet<K> keySet() { 711 ImmutableSet<K> result = keySet; 712 return (result == null) ? keySet = createKeySet() : result; 713 } 714 715 /* 716 * This could have a good default implementation of return new ImmutableKeySet<K, V>(this), 717 * but ProGuard can't figure out how to eliminate that default when RegularImmutableMap 718 * overrides it. 719 */ 720 abstract ImmutableSet<K> createKeySet(); 721 722 UnmodifiableIterator<K> keyIterator() { 723 final UnmodifiableIterator<Entry<K, V>> entryIterator = entrySet().iterator(); 724 return new UnmodifiableIterator<K>() { 725 @Override 726 public boolean hasNext() { 727 return entryIterator.hasNext(); 728 } 729 730 @Override 731 public K next() { 732 return entryIterator.next().getKey(); 733 } 734 }; 735 } 736 737 Spliterator<K> keySpliterator() { 738 return CollectSpliterators.map(entrySet().spliterator(), Entry::getKey); 739 } 740 741 @LazyInit private transient ImmutableCollection<V> values; 742 743 /** 744 * Returns an immutable collection of the values in this map, in the same order that they appear 745 * in {@link #entrySet}. 746 */ 747 @Override 748 public ImmutableCollection<V> values() { 749 ImmutableCollection<V> result = values; 750 return (result == null) ? values = createValues() : result; 751 } 752 753 /* 754 * This could have a good default implementation of {@code return new 755 * ImmutableMapValues<K, V>(this)}, but ProGuard can't figure out how to eliminate that default 756 * when RegularImmutableMap overrides it. 757 */ 758 abstract ImmutableCollection<V> createValues(); 759 760 // cached so that this.multimapView().inverse() only computes inverse once 761 @LazyInit private transient ImmutableSetMultimap<K, V> multimapView; 762 763 /** 764 * Returns a multimap view of the map. 765 * 766 * @since 14.0 767 */ 768 public ImmutableSetMultimap<K, V> asMultimap() { 769 if (isEmpty()) { 770 return ImmutableSetMultimap.of(); 771 } 772 ImmutableSetMultimap<K, V> result = multimapView; 773 return (result == null) 774 ? (multimapView = 775 new ImmutableSetMultimap<>(new MapViewOfValuesAsSingletonSets(), size(), null)) 776 : result; 777 } 778 779 @WeakOuter 780 private final class MapViewOfValuesAsSingletonSets 781 extends IteratorBasedImmutableMap<K, ImmutableSet<V>> { 782 783 @Override 784 public int size() { 785 return ImmutableMap.this.size(); 786 } 787 788 @Override 789 ImmutableSet<K> createKeySet() { 790 return ImmutableMap.this.keySet(); 791 } 792 793 @Override 794 public boolean containsKey(@NullableDecl Object key) { 795 return ImmutableMap.this.containsKey(key); 796 } 797 798 @Override 799 public ImmutableSet<V> get(@NullableDecl Object key) { 800 V outerValue = ImmutableMap.this.get(key); 801 return (outerValue == null) ? null : ImmutableSet.of(outerValue); 802 } 803 804 @Override 805 boolean isPartialView() { 806 return ImmutableMap.this.isPartialView(); 807 } 808 809 @Override 810 public int hashCode() { 811 // ImmutableSet.of(value).hashCode() == value.hashCode(), so the hashes are the same 812 return ImmutableMap.this.hashCode(); 813 } 814 815 @Override 816 boolean isHashCodeFast() { 817 return ImmutableMap.this.isHashCodeFast(); 818 } 819 820 @Override 821 UnmodifiableIterator<Entry<K, ImmutableSet<V>>> entryIterator() { 822 final Iterator<Entry<K, V>> backingIterator = ImmutableMap.this.entrySet().iterator(); 823 return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() { 824 @Override 825 public boolean hasNext() { 826 return backingIterator.hasNext(); 827 } 828 829 @Override 830 public Entry<K, ImmutableSet<V>> next() { 831 final Entry<K, V> backingEntry = backingIterator.next(); 832 return new AbstractMapEntry<K, ImmutableSet<V>>() { 833 @Override 834 public K getKey() { 835 return backingEntry.getKey(); 836 } 837 838 @Override 839 public ImmutableSet<V> getValue() { 840 return ImmutableSet.of(backingEntry.getValue()); 841 } 842 }; 843 } 844 }; 845 } 846 } 847 848 @Override 849 public boolean equals(@NullableDecl Object object) { 850 return Maps.equalsImpl(this, object); 851 } 852 853 abstract boolean isPartialView(); 854 855 @Override 856 public int hashCode() { 857 return Sets.hashCodeImpl(entrySet()); 858 } 859 860 boolean isHashCodeFast() { 861 return false; 862 } 863 864 @Override 865 public String toString() { 866 return Maps.toStringImpl(this); 867 } 868 869 /** 870 * Serialized type for all ImmutableMap instances. It captures the logical contents and they are 871 * reconstructed using public factory methods. This ensures that the implementation types remain 872 * as implementation details. 873 */ 874 static class SerializedForm implements Serializable { 875 private final Object[] keys; 876 private final Object[] values; 877 878 SerializedForm(ImmutableMap<?, ?> map) { 879 keys = new Object[map.size()]; 880 values = new Object[map.size()]; 881 int i = 0; 882 for (Entry<?, ?> entry : map.entrySet()) { 883 keys[i] = entry.getKey(); 884 values[i] = entry.getValue(); 885 i++; 886 } 887 } 888 889 Object readResolve() { 890 Builder<Object, Object> builder = new Builder<>(keys.length); 891 return createMap(builder); 892 } 893 894 Object createMap(Builder<Object, Object> builder) { 895 for (int i = 0; i < keys.length; i++) { 896 builder.put(keys[i], values[i]); 897 } 898 return builder.build(); 899 } 900 901 private static final long serialVersionUID = 0; 902 } 903 904 Object writeReplace() { 905 return new SerializedForm(this); 906 } 907}