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.DoNotMock; 028import com.google.errorprone.annotations.concurrent.LazyInit; 029import com.google.j2objc.annotations.RetainedWith; 030import com.google.j2objc.annotations.WeakOuter; 031import java.io.Serializable; 032import java.util.AbstractMap; 033import java.util.Arrays; 034import java.util.Collection; 035import java.util.Collections; 036import java.util.Comparator; 037import java.util.Iterator; 038import java.util.Map; 039import java.util.Map.Entry; 040import java.util.SortedMap; 041import org.checkerframework.checker.nullness.compatqual.NullableDecl; 042 043/** 044 * A {@link Map} whose contents will never change, with many other important properties detailed at 045 * {@link ImmutableCollection}. 046 * 047 * <p>See the Guava User Guide article on <a href= 048 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>. 049 * 050 * @author Jesse Wilson 051 * @author Kevin Bourrillion 052 * @since 2.0 053 */ 054@DoNotMock("Use ImmutableMap.of or another implementation") 055@GwtCompatible(serializable = true, emulated = true) 056@SuppressWarnings("serial") // we're overriding default serialization 057public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable { 058 059 /** 060 * Returns the empty map. This map behaves and performs comparably to {@link 061 * Collections#emptyMap}, and is preferable mainly for consistency and maintainability of your 062 * code. 063 */ 064 @SuppressWarnings("unchecked") 065 public static <K, V> ImmutableMap<K, V> of() { 066 return (ImmutableMap<K, V>) RegularImmutableMap.EMPTY; 067 } 068 069 /** 070 * Returns an immutable map containing a single entry. This map behaves and performs comparably to 071 * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable 072 * mainly for consistency and maintainability of your code. 073 */ 074 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) { 075 checkEntryNotNull(k1, v1); 076 return RegularImmutableMap.create(1, new Object[] {k1, v1}); 077 } 078 079 /** 080 * Returns an immutable map containing the given entries, in order. 081 * 082 * @throws IllegalArgumentException if duplicate keys are provided 083 */ 084 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) { 085 checkEntryNotNull(k1, v1); 086 checkEntryNotNull(k2, v2); 087 return RegularImmutableMap.create(2, new Object[] {k1, v1, k2, v2}); 088 } 089 090 /** 091 * Returns an immutable map containing the given entries, in order. 092 * 093 * @throws IllegalArgumentException if duplicate keys are provided 094 */ 095 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 096 checkEntryNotNull(k1, v1); 097 checkEntryNotNull(k2, v2); 098 checkEntryNotNull(k3, v3); 099 return RegularImmutableMap.create(3, new Object[] {k1, v1, k2, v2, k3, v3}); 100 } 101 102 /** 103 * Returns an immutable map containing the given entries, in order. 104 * 105 * @throws IllegalArgumentException if duplicate keys are provided 106 */ 107 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 108 checkEntryNotNull(k1, v1); 109 checkEntryNotNull(k2, v2); 110 checkEntryNotNull(k3, v3); 111 checkEntryNotNull(k4, v4); 112 return RegularImmutableMap.create(4, new Object[] {k1, v1, k2, v2, k3, v3, k4, v4}); 113 } 114 115 /** 116 * Returns an immutable map containing the given entries, in order. 117 * 118 * @throws IllegalArgumentException if duplicate keys are provided 119 */ 120 public static <K, V> ImmutableMap<K, V> of( 121 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 122 checkEntryNotNull(k1, v1); 123 checkEntryNotNull(k2, v2); 124 checkEntryNotNull(k3, v3); 125 checkEntryNotNull(k4, v4); 126 checkEntryNotNull(k5, v5); 127 return RegularImmutableMap.create(5, new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5}); 128 } 129 130 // looking for of() with > 5 entries? Use the builder instead. 131 132 /** 133 * Verifies that {@code key} and {@code value} are non-null, and returns a new immutable entry 134 * with those values. 135 * 136 * <p>A call to {@link Entry#setValue} on the returned entry will always throw {@link 137 * UnsupportedOperationException}. 138 */ 139 static <K, V> Entry<K, V> entryOf(K key, V value) { 140 checkEntryNotNull(key, value); 141 return new AbstractMap.SimpleImmutableEntry<>(key, value); 142 } 143 144 /** 145 * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 146 * Builder} constructor. 147 */ 148 public static <K, V> Builder<K, V> builder() { 149 return new Builder<>(); 150 } 151 152 /** 153 * Returns a new builder, expecting the specified number of entries to be added. 154 * 155 * <p>If {@code expectedSize} is exactly the number of entries added to the builder before {@link 156 * Builder#build} is called, the builder is likely to perform better than an unsized {@link 157 * #builder()} would have. 158 * 159 * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to, 160 * but not exactly, the number of entries added to the builder. 161 * 162 * @since 23.1 163 */ 164 @Beta 165 public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) { 166 checkNonnegative(expectedSize, "expectedSize"); 167 return new Builder<>(expectedSize); 168 } 169 170 static void checkNoConflict( 171 boolean safe, String conflictDescription, Entry<?, ?> entry1, Entry<?, ?> entry2) { 172 if (!safe) { 173 throw conflictException(conflictDescription, entry1, entry2); 174 } 175 } 176 177 static IllegalArgumentException conflictException( 178 String conflictDescription, Object entry1, Object entry2) { 179 return new IllegalArgumentException( 180 "Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2); 181 } 182 183 /** 184 * A builder for creating immutable map instances, especially {@code public static final} maps 185 * ("constant maps"). Example: 186 * 187 * <pre>{@code 188 * static final ImmutableMap<String, Integer> WORD_TO_INT = 189 * new ImmutableMap.Builder<String, Integer>() 190 * .put("one", 1) 191 * .put("two", 2) 192 * .put("three", 3) 193 * .build(); 194 * }</pre> 195 * 196 * <p>For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are even more 197 * convenient. 198 * 199 * <p>By default, a {@code Builder} will generate maps that iterate over entries in the order they 200 * were inserted into the builder, equivalently to {@code LinkedHashMap}. For example, in the 201 * above example, {@code WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the 202 * order {@code "one"=1, "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect 203 * the same order. If you want a different order, consider using {@link ImmutableSortedMap} to 204 * sort by keys, or call {@link #orderEntriesByValue(Comparator)}, which changes this builder to 205 * sort entries by value. 206 * 207 * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build 208 * multiple maps in series. Each map is a superset of the maps created before it. 209 * 210 * @since 2.0 211 */ 212 @DoNotMock 213 public static class Builder<K, V> { 214 @NullableDecl Comparator<? super V> valueComparator; 215 Object[] alternatingKeysAndValues; 216 int size; 217 boolean entriesUsed; 218 219 /** 220 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 221 * ImmutableMap#builder}. 222 */ 223 public Builder() { 224 this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY); 225 } 226 227 @SuppressWarnings("unchecked") 228 Builder(int initialCapacity) { 229 this.alternatingKeysAndValues = new Object[2 * initialCapacity]; 230 this.size = 0; 231 this.entriesUsed = false; 232 } 233 234 private void ensureCapacity(int minCapacity) { 235 if (minCapacity * 2 > alternatingKeysAndValues.length) { 236 alternatingKeysAndValues = 237 Arrays.copyOf( 238 alternatingKeysAndValues, 239 ImmutableCollection.Builder.expandedCapacity( 240 alternatingKeysAndValues.length, minCapacity * 2)); 241 entriesUsed = false; 242 } 243 } 244 245 /** 246 * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed, 247 * 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 checkEntryNotNull(key, value); 253 alternatingKeysAndValues[2 * size] = key; 254 alternatingKeysAndValues[2 * size + 1] = value; 255 size++; 256 return this; 257 } 258 259 /** 260 * Adds the given {@code entry} to the map, making it immutable if necessary. Duplicate keys are 261 * not allowed, and will cause {@link #build} 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. Duplicate keys are not 272 * 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 allowed, and will 283 * 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 as equivalent, 305 * the entry that was inserted first will be first in the built map's iteration order. 306 * 307 * @throws IllegalStateException if this method was already called 308 * @since 19.0 309 */ 310 @CanIgnoreReturnValue 311 @Beta 312 public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) { 313 checkState(this.valueComparator == null, "valueComparator was already set"); 314 this.valueComparator = checkNotNull(valueComparator, "valueComparator"); 315 return this; 316 } 317 318 @CanIgnoreReturnValue 319 Builder<K, V> combine(Builder<K, V> other) { 320 checkNotNull(other); 321 ensureCapacity(this.size + other.size); 322 System.arraycopy( 323 other.alternatingKeysAndValues, 324 0, 325 this.alternatingKeysAndValues, 326 this.size * 2, 327 other.size * 2); 328 this.size += other.size; 329 return this; 330 } 331 332 /* 333 * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap 334 * versions throw an IllegalStateException instead? 335 */ 336 337 /** 338 * Returns a newly-created immutable map. The iteration order of the returned map is the order 339 * in which entries were inserted into the builder, unless {@link #orderEntriesByValue} was 340 * called, in which case entries are sorted by value. 341 * 342 * @throws IllegalArgumentException if duplicate keys were added 343 */ 344 @SuppressWarnings("unchecked") 345 public ImmutableMap<K, V> build() { 346 /* 347 * If entries is full, then this implementation may end up using the entries array 348 * directly and writing over the entry objects with non-terminal entries, but this is 349 * safe; if this Builder is used further, it will grow the entries array (so it can't 350 * affect the original array), and future build() calls will always copy any entry 351 * objects that cannot be safely reused. 352 */ 353 sortEntries(); 354 entriesUsed = true; 355 return RegularImmutableMap.create(size, alternatingKeysAndValues); 356 } 357 358 void sortEntries() { 359 if (valueComparator != null) { 360 if (entriesUsed) { 361 alternatingKeysAndValues = Arrays.copyOf(alternatingKeysAndValues, 2 * size); 362 } 363 Entry<K, V>[] entries = new Entry[size]; 364 for (int i = 0; i < size; i++) { 365 entries[i] = 366 new AbstractMap.SimpleImmutableEntry<K, V>( 367 (K) alternatingKeysAndValues[2 * i], (V) alternatingKeysAndValues[2 * i + 1]); 368 } 369 Arrays.sort( 370 entries, 0, size, Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction())); 371 for (int i = 0; i < size; i++) { 372 alternatingKeysAndValues[2 * i] = entries[i].getKey(); 373 alternatingKeysAndValues[2 * i + 1] = entries[i].getValue(); 374 } 375 } 376 } 377 } 378 379 /** 380 * Returns an immutable map containing the same entries as {@code map}. The returned map iterates 381 * over entries in the same order as the {@code entrySet} of the original map. If {@code map} 382 * somehow contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose 383 * comparator is not <i>consistent with equals</i>), the results of this method are undefined. 384 * 385 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 386 * safe to do so. The exact circumstances under which a copy will or will not be performed are 387 * undocumented and subject to change. 388 * 389 * @throws NullPointerException if any key or value in {@code map} is null 390 */ 391 public static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V> map) { 392 if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) { 393 @SuppressWarnings("unchecked") // safe since map is not writable 394 ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map; 395 if (!kvMap.isPartialView()) { 396 return kvMap; 397 } 398 } 399 return copyOf(map.entrySet()); 400 } 401 402 /** 403 * Returns an immutable map containing the specified entries. The returned map iterates over 404 * entries in the same order as the original iterable. 405 * 406 * @throws NullPointerException if any key, value, or entry is null 407 * @throws IllegalArgumentException if two entries have the same key 408 * @since 19.0 409 */ 410 @Beta 411 public static <K, V> ImmutableMap<K, V> copyOf( 412 Iterable<? extends Entry<? extends K, ? extends V>> entries) { 413 int initialCapacity = 414 (entries instanceof Collection) 415 ? ((Collection<?>) entries).size() 416 : ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY; 417 ImmutableMap.Builder<K, V> builder = new ImmutableMap.Builder<K, V>(initialCapacity); 418 builder.putAll(entries); 419 return builder.build(); 420 } 421 422 static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0]; 423 424 abstract static class IteratorBasedImmutableMap<K, V> extends ImmutableMap<K, V> { 425 abstract UnmodifiableIterator<Entry<K, V>> entryIterator(); 426 427 @Override 428 ImmutableSet<K> createKeySet() { 429 return new ImmutableMapKeySet<>(this); 430 } 431 432 @Override 433 ImmutableSet<Entry<K, V>> createEntrySet() { 434 class EntrySetImpl extends ImmutableMapEntrySet<K, V> { 435 @Override 436 ImmutableMap<K, V> map() { 437 return IteratorBasedImmutableMap.this; 438 } 439 440 @Override 441 public UnmodifiableIterator<Entry<K, V>> iterator() { 442 return entryIterator(); 443 } 444 } 445 return new EntrySetImpl(); 446 } 447 448 @Override 449 ImmutableCollection<V> createValues() { 450 return new ImmutableMapValues<>(this); 451 } 452 } 453 454 ImmutableMap() {} 455 456 /** 457 * Guaranteed to throw an exception and leave the map unmodified. 458 * 459 * @throws UnsupportedOperationException always 460 * @deprecated Unsupported operation. 461 */ 462 @CanIgnoreReturnValue 463 @Deprecated 464 @Override 465 public final V put(K k, V v) { 466 throw new UnsupportedOperationException(); 467 } 468 469 /** 470 * Guaranteed to throw an exception and leave the map unmodified. 471 * 472 * @throws UnsupportedOperationException always 473 * @deprecated Unsupported operation. 474 */ 475 @CanIgnoreReturnValue 476 @Deprecated 477 @Override 478 public final V remove(Object o) { 479 throw new UnsupportedOperationException(); 480 } 481 482 /** 483 * Guaranteed to throw an exception and leave the map unmodified. 484 * 485 * @throws UnsupportedOperationException always 486 * @deprecated Unsupported operation. 487 */ 488 @Deprecated 489 @Override 490 public final void putAll(Map<? extends K, ? extends V> map) { 491 throw new UnsupportedOperationException(); 492 } 493 494 /** 495 * Guaranteed to throw an exception and leave the map unmodified. 496 * 497 * @throws UnsupportedOperationException always 498 * @deprecated Unsupported operation. 499 */ 500 @Deprecated 501 @Override 502 public final void clear() { 503 throw new UnsupportedOperationException(); 504 } 505 506 @Override 507 public boolean isEmpty() { 508 return size() == 0; 509 } 510 511 @Override 512 public boolean containsKey(@NullableDecl Object key) { 513 return get(key) != null; 514 } 515 516 @Override 517 public boolean containsValue(@NullableDecl Object value) { 518 return values().contains(value); 519 } 520 521 // Overriding to mark it Nullable 522 @Override 523 public abstract V get(@NullableDecl Object key); 524 525 /** 526 * {@inheritDoc} 527 * 528 * <p>See <a 529 * href="https://developer.android.com/reference/java/util/Map.html#getOrDefault%28java.lang.Object,%20V%29">{@code 530 * Map.getOrDefault}</a>. 531 * 532 * @since 23.5 (but since 21.0 in the JRE <a 533 * href="https://github.com/google/guava#guava-google-core-libraries-for-java">flavor</a>). 534 * Note that API Level 24 users can call this method with any version of Guava. 535 */ 536 // @Override under Java 8 / API Level 24 537 public final V getOrDefault(@NullableDecl Object key, @NullableDecl V defaultValue) { 538 V result = get(key); 539 return (result != null) ? result : defaultValue; 540 } 541 542 @LazyInit @RetainedWith private transient ImmutableSet<Entry<K, V>> entrySet; 543 544 /** 545 * Returns an immutable set of the mappings in this map. The iteration order is specified by the 546 * method used to create this map. Typically, this is insertion order. 547 */ 548 @Override 549 public ImmutableSet<Entry<K, V>> entrySet() { 550 ImmutableSet<Entry<K, V>> result = entrySet; 551 return (result == null) ? entrySet = createEntrySet() : result; 552 } 553 554 abstract ImmutableSet<Entry<K, V>> createEntrySet(); 555 556 @LazyInit @RetainedWith private transient ImmutableSet<K> keySet; 557 558 /** 559 * Returns an immutable set of the keys in this map, in the same order that they appear in {@link 560 * #entrySet}. 561 */ 562 @Override 563 public ImmutableSet<K> keySet() { 564 ImmutableSet<K> result = keySet; 565 return (result == null) ? keySet = createKeySet() : result; 566 } 567 568 /* 569 * This could have a good default implementation of return new ImmutableKeySet<K, V>(this), 570 * but ProGuard can't figure out how to eliminate that default when RegularImmutableMap 571 * overrides it. 572 */ 573 abstract ImmutableSet<K> createKeySet(); 574 575 UnmodifiableIterator<K> keyIterator() { 576 final UnmodifiableIterator<Entry<K, V>> entryIterator = entrySet().iterator(); 577 return new UnmodifiableIterator<K>() { 578 @Override 579 public boolean hasNext() { 580 return entryIterator.hasNext(); 581 } 582 583 @Override 584 public K next() { 585 return entryIterator.next().getKey(); 586 } 587 }; 588 } 589 590 @LazyInit @RetainedWith private transient ImmutableCollection<V> values; 591 592 /** 593 * Returns an immutable collection of the values in this map, in the same order that they appear 594 * in {@link #entrySet}. 595 */ 596 @Override 597 public ImmutableCollection<V> values() { 598 ImmutableCollection<V> result = values; 599 return (result == null) ? values = createValues() : result; 600 } 601 602 /* 603 * This could have a good default implementation of {@code return new 604 * ImmutableMapValues<K, V>(this)}, but ProGuard can't figure out how to eliminate that default 605 * when RegularImmutableMap overrides it. 606 */ 607 abstract ImmutableCollection<V> createValues(); 608 609 // cached so that this.multimapView().inverse() only computes inverse once 610 @LazyInit private transient ImmutableSetMultimap<K, V> multimapView; 611 612 /** 613 * Returns a multimap view of the map. 614 * 615 * @since 14.0 616 */ 617 public ImmutableSetMultimap<K, V> asMultimap() { 618 if (isEmpty()) { 619 return ImmutableSetMultimap.of(); 620 } 621 ImmutableSetMultimap<K, V> result = multimapView; 622 return (result == null) 623 ? (multimapView = 624 new ImmutableSetMultimap<>(new MapViewOfValuesAsSingletonSets(), size(), null)) 625 : result; 626 } 627 628 @WeakOuter 629 private final class MapViewOfValuesAsSingletonSets 630 extends IteratorBasedImmutableMap<K, ImmutableSet<V>> { 631 632 @Override 633 public int size() { 634 return ImmutableMap.this.size(); 635 } 636 637 @Override 638 ImmutableSet<K> createKeySet() { 639 return ImmutableMap.this.keySet(); 640 } 641 642 @Override 643 public boolean containsKey(@NullableDecl Object key) { 644 return ImmutableMap.this.containsKey(key); 645 } 646 647 @Override 648 public ImmutableSet<V> get(@NullableDecl Object key) { 649 V outerValue = ImmutableMap.this.get(key); 650 return (outerValue == null) ? null : ImmutableSet.of(outerValue); 651 } 652 653 @Override 654 boolean isPartialView() { 655 return ImmutableMap.this.isPartialView(); 656 } 657 658 @Override 659 public int hashCode() { 660 // ImmutableSet.of(value).hashCode() == value.hashCode(), so the hashes are the same 661 return ImmutableMap.this.hashCode(); 662 } 663 664 @Override 665 boolean isHashCodeFast() { 666 return ImmutableMap.this.isHashCodeFast(); 667 } 668 669 @Override 670 UnmodifiableIterator<Entry<K, ImmutableSet<V>>> entryIterator() { 671 final Iterator<Entry<K, V>> backingIterator = ImmutableMap.this.entrySet().iterator(); 672 return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() { 673 @Override 674 public boolean hasNext() { 675 return backingIterator.hasNext(); 676 } 677 678 @Override 679 public Entry<K, ImmutableSet<V>> next() { 680 final Entry<K, V> backingEntry = backingIterator.next(); 681 return new AbstractMapEntry<K, ImmutableSet<V>>() { 682 @Override 683 public K getKey() { 684 return backingEntry.getKey(); 685 } 686 687 @Override 688 public ImmutableSet<V> getValue() { 689 return ImmutableSet.of(backingEntry.getValue()); 690 } 691 }; 692 } 693 }; 694 } 695 } 696 697 @Override 698 public boolean equals(@NullableDecl Object object) { 699 return Maps.equalsImpl(this, object); 700 } 701 702 abstract boolean isPartialView(); 703 704 @Override 705 public int hashCode() { 706 return Sets.hashCodeImpl(entrySet()); 707 } 708 709 boolean isHashCodeFast() { 710 return false; 711 } 712 713 @Override 714 public String toString() { 715 return Maps.toStringImpl(this); 716 } 717 718 /** 719 * Serialized type for all ImmutableMap instances. It captures the logical contents and they are 720 * reconstructed using public factory methods. This ensures that the implementation types remain 721 * as implementation details. 722 */ 723 static class SerializedForm<K, V> implements Serializable { 724 // This object retains references to collections returned by keySet() and value(). This saves 725 // bytes when the both the map and its keySet or value collection are written to the same 726 // instance of ObjectOutputStream. 727 728 // TODO(b/160980469): remove support for the old serialization format after some time 729 private static final boolean USE_LEGACY_SERIALIZATION = true; 730 731 private final Object keys; 732 private final Object values; 733 734 SerializedForm(ImmutableMap<K, V> map) { 735 if (USE_LEGACY_SERIALIZATION) { 736 Object[] keys = new Object[map.size()]; 737 Object[] values = new Object[map.size()]; 738 int i = 0; 739 for (Entry<?, ?> entry : map.entrySet()) { 740 keys[i] = entry.getKey(); 741 values[i] = entry.getValue(); 742 i++; 743 } 744 this.keys = keys; 745 this.values = values; 746 return; 747 } 748 this.keys = map.keySet(); 749 this.values = map.values(); 750 } 751 752 @SuppressWarnings("unchecked") 753 final Object readResolve() { 754 if (!(this.keys instanceof ImmutableSet)) { 755 return legacyReadResolve(); 756 } 757 758 ImmutableSet<K> keySet = (ImmutableSet<K>) this.keys; 759 ImmutableCollection<V> values = (ImmutableCollection<V>) this.values; 760 761 Builder<K, V> builder = makeBuilder(keySet.size()); 762 763 UnmodifiableIterator<K> keyIter = keySet.iterator(); 764 UnmodifiableIterator<V> valueIter = values.iterator(); 765 766 while (keyIter.hasNext()) { 767 builder.put(keyIter.next(), valueIter.next()); 768 } 769 770 return builder.build(); 771 } 772 773 @SuppressWarnings("unchecked") 774 final Object legacyReadResolve() { 775 K[] keys = (K[]) this.keys; 776 V[] values = (V[]) this.values; 777 778 Builder<K, V> builder = makeBuilder(keys.length); 779 780 for (int i = 0; i < keys.length; i++) { 781 builder.put(keys[i], values[i]); 782 } 783 return builder.build(); 784 } 785 786 /** 787 * Returns a builder that builds the unserialized type. Subclasses should override this method. 788 */ 789 Builder<K, V> makeBuilder(int size) { 790 return new Builder<>(size); 791 } 792 793 private static final long serialVersionUID = 0; 794 } 795 796 /** 797 * Returns a serializable form of this object. Non-public subclasses should not override this 798 * method. Publicly-accessible subclasses must override this method and should return a subclass 799 * of SerializedForm whose readResolve() method returns objects of the subclass type. 800 */ 801 Object writeReplace() { 802 return new SerializedForm<>(this); 803 } 804}