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