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