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.collect.CollectPreconditions.checkEntryNotNull; 021 022import com.google.common.annotations.Beta; 023import com.google.common.annotations.GwtCompatible; 024import com.google.common.annotations.GwtIncompatible; 025import com.google.errorprone.annotations.CanIgnoreReturnValue; 026import com.google.j2objc.annotations.Weak; 027import com.google.j2objc.annotations.WeakOuter; 028 029import java.io.Serializable; 030import java.util.Arrays; 031import java.util.Collection; 032import java.util.Collections; 033import java.util.Comparator; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Map; 037import java.util.Map.Entry; 038import javax.annotation.Nullable; 039 040/** 041 * A {@link Multimap} whose contents will never change, with many other important properties 042 * detailed at {@link ImmutableCollection}. 043 * 044 * <p><b>Warning:</b> avoid <i>direct</i> usage of {@link ImmutableMultimap} as a type (as with 045 * {@link Multimap} itself). Prefer subtypes such as {@link ImmutableSetMultimap} or {@link 046 * ImmutableListMultimap}, which have well-defined {@link #equals} semantics, thus avoiding a common 047 * source of bugs and confusion. 048 * 049 * <p><b>Note:</b> every {@link ImmutableMultimap} offers an {@link #inverse} view, so there is no 050 * need for a distinct {@code ImmutableBiMultimap} type. 051 * 052 * <a name="iteration"></a> 053 * <p><b>Key-grouped iteration.</b> All view collections follow the same iteration order. In all 054 * current implementations, the iteration order always keeps multiple entries with the same key 055 * together. Any creation method that would customarily respect insertion order (such as {@link 056 * #copyOf(Multimap)}) instead preserves key-grouped order by inserting entries for an existing key 057 * immediately after the last entry having that key. 058 * 059 * <p>See the Guava User Guide article on <a href= 060 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> 061 * immutable collections</a>. 062 * 063 * @author Jared Levy 064 * @since 2.0 065 */ 066@GwtCompatible(emulated = true) 067public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V> 068 implements Serializable { 069 070 /** Returns an empty multimap. */ 071 public static <K, V> ImmutableMultimap<K, V> of() { 072 return ImmutableListMultimap.of(); 073 } 074 075 /** 076 * Returns an immutable multimap containing a single entry. 077 */ 078 public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1) { 079 return ImmutableListMultimap.of(k1, v1); 080 } 081 082 /** 083 * Returns an immutable multimap containing the given entries, in order. 084 */ 085 public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2) { 086 return ImmutableListMultimap.of(k1, v1, k2, v2); 087 } 088 089 /** 090 * Returns an immutable multimap containing the given entries, in the 091 * "key-grouped" insertion order described in the 092 * <a href="#iteration">class documentation</a>. 093 */ 094 public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 095 return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3); 096 } 097 098 /** 099 * Returns an immutable multimap containing the given entries, in the 100 * "key-grouped" insertion order described in the 101 * <a href="#iteration">class documentation</a>. 102 */ 103 public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 104 return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4); 105 } 106 107 /** 108 * Returns an immutable multimap containing the given entries, in the 109 * "key-grouped" insertion order described in the 110 * <a href="#iteration">class documentation</a>. 111 */ 112 public static <K, V> ImmutableMultimap<K, V> of( 113 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 114 return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); 115 } 116 117 // looking for of() with > 5 entries? Use the builder instead. 118 119 /** 120 * Returns a new builder. The generated builder is equivalent to the builder 121 * created by the {@link Builder} constructor. 122 */ 123 public static <K, V> Builder<K, V> builder() { 124 return new Builder<>(); 125 } 126 127 /** 128 * A builder for creating immutable multimap instances, especially 129 * {@code public static final} multimaps ("constant multimaps"). Example: 130 * <pre> {@code 131 * 132 * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP = 133 * new ImmutableMultimap.Builder<String, Integer>() 134 * .put("one", 1) 135 * .putAll("several", 1, 2, 3) 136 * .putAll("many", 1, 2, 3, 4, 5) 137 * .build();}</pre> 138 * 139 * <p>Builder instances can be reused; it is safe to call {@link #build} multiple 140 * times to build multiple multimaps in series. Each multimap contains the 141 * key-value mappings in the previously created multimaps. 142 * 143 * @since 2.0 144 */ 145 public static class Builder<K, V> { 146 Multimap<K, V> builderMultimap; 147 Comparator<? super K> keyComparator; 148 Comparator<? super V> valueComparator; 149 150 /** 151 * Creates a new builder. The returned builder is equivalent to the builder 152 * generated by {@link ImmutableMultimap#builder}. 153 */ 154 public Builder() { 155 this(MultimapBuilder.linkedHashKeys().arrayListValues().<K, V>build()); 156 } 157 158 Builder(Multimap<K, V> builderMultimap) { 159 this.builderMultimap = builderMultimap; 160 } 161 162 /** 163 * Adds a key-value mapping to the built multimap. 164 */ 165 @CanIgnoreReturnValue 166 public Builder<K, V> put(K key, V value) { 167 checkEntryNotNull(key, value); 168 builderMultimap.put(key, value); 169 return this; 170 } 171 172 /** 173 * Adds an entry to the built multimap. 174 * 175 * @since 11.0 176 */ 177 @CanIgnoreReturnValue 178 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 179 return put(entry.getKey(), entry.getValue()); 180 } 181 182 /** 183 * Adds entries to the built multimap. 184 * 185 * @since 19.0 186 */ 187 @CanIgnoreReturnValue 188 @Beta 189 public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) { 190 for (Entry<? extends K, ? extends V> entry : entries) { 191 put(entry); 192 } 193 return this; 194 } 195 196 /** 197 * Stores a collection of values with the same key in the built multimap. 198 * 199 * @throws NullPointerException if {@code key}, {@code values}, or any 200 * element in {@code values} is null. The builder is left in an invalid 201 * state. 202 */ 203 @CanIgnoreReturnValue 204 public Builder<K, V> putAll(K key, Iterable<? extends V> values) { 205 if (key == null) { 206 throw new NullPointerException("null key in entry: null=" + Iterables.toString(values)); 207 } 208 Collection<V> valueList = builderMultimap.get(key); 209 for (V value : values) { 210 checkEntryNotNull(key, value); 211 valueList.add(value); 212 } 213 return this; 214 } 215 216 /** 217 * Stores an array of values with the same key in the built multimap. 218 * 219 * @throws NullPointerException if the key or any value is null. The builder 220 * is left in an invalid state. 221 */ 222 @CanIgnoreReturnValue 223 public Builder<K, V> putAll(K key, V... values) { 224 return putAll(key, Arrays.asList(values)); 225 } 226 227 /** 228 * Stores another multimap's entries in the built multimap. The generated 229 * multimap's key and value orderings correspond to the iteration ordering 230 * of the {@code multimap.asMap()} view, with new keys and values following 231 * any existing keys and values. 232 * 233 * @throws NullPointerException if any key or value in {@code multimap} is 234 * null. The builder is left in an invalid state. 235 */ 236 @CanIgnoreReturnValue 237 public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) { 238 for (Entry<? extends K, ? extends Collection<? extends V>> entry : 239 multimap.asMap().entrySet()) { 240 putAll(entry.getKey(), entry.getValue()); 241 } 242 return this; 243 } 244 245 /** 246 * Specifies the ordering of the generated multimap's keys. 247 * 248 * @since 8.0 249 */ 250 @CanIgnoreReturnValue 251 public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) { 252 this.keyComparator = checkNotNull(keyComparator); 253 return this; 254 } 255 256 /** 257 * Specifies the ordering of the generated multimap's values for each key. 258 * 259 * @since 8.0 260 */ 261 @CanIgnoreReturnValue 262 public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) { 263 this.valueComparator = checkNotNull(valueComparator); 264 return this; 265 } 266 267 /** 268 * Returns a newly-created immutable multimap. 269 */ 270 public ImmutableMultimap<K, V> build() { 271 if (valueComparator != null) { 272 for (Collection<V> values : builderMultimap.asMap().values()) { 273 List<V> list = (List<V>) values; 274 Collections.sort(list, valueComparator); 275 } 276 } 277 if (keyComparator != null) { 278 Multimap<K, V> sortedCopy = 279 MultimapBuilder.linkedHashKeys().arrayListValues().<K, V>build(); 280 List<Map.Entry<K, Collection<V>>> entries = 281 Ordering.from(keyComparator) 282 .<K>onKeys() 283 .immutableSortedCopy(builderMultimap.asMap().entrySet()); 284 for (Map.Entry<K, Collection<V>> entry : entries) { 285 sortedCopy.putAll(entry.getKey(), entry.getValue()); 286 } 287 builderMultimap = sortedCopy; 288 } 289 return copyOf(builderMultimap); 290 } 291 } 292 293 /** 294 * Returns an immutable multimap containing the same mappings as {@code 295 * multimap}, in the "key-grouped" iteration order described in the class 296 * documentation. 297 * 298 * <p>Despite the method name, this method attempts to avoid actually copying 299 * the data when it is safe to do so. The exact circumstances under which a 300 * copy will or will not be performed are undocumented and subject to change. 301 * 302 * @throws NullPointerException if any key or value in {@code multimap} is 303 * null 304 */ 305 public static <K, V> ImmutableMultimap<K, V> copyOf(Multimap<? extends K, ? extends V> multimap) { 306 if (multimap instanceof ImmutableMultimap) { 307 @SuppressWarnings("unchecked") // safe since multimap is not writable 308 ImmutableMultimap<K, V> kvMultimap = (ImmutableMultimap<K, V>) multimap; 309 if (!kvMultimap.isPartialView()) { 310 return kvMultimap; 311 } 312 } 313 return ImmutableListMultimap.copyOf(multimap); 314 } 315 316 /** 317 * Returns an immutable multimap containing the specified entries. The 318 * returned multimap iterates over keys in the order they were first 319 * encountered in the input, and the values for each key are iterated in the 320 * order they were encountered. 321 * 322 * @throws NullPointerException if any key, value, or entry is null 323 * @since 19.0 324 */ 325 @Beta 326 public static <K, V> ImmutableMultimap<K, V> copyOf( 327 Iterable<? extends Entry<? extends K, ? extends V>> entries) { 328 return ImmutableListMultimap.copyOf(entries); 329 } 330 331 final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map; 332 final transient int size; 333 334 // These constants allow the deserialization code to set final fields. This 335 // holder class makes sure they are not initialized unless an instance is 336 // deserialized. 337 @GwtIncompatible // java serialization is not supported 338 static class FieldSettersHolder { 339 static final Serialization.FieldSetter<ImmutableMultimap> MAP_FIELD_SETTER = 340 Serialization.getFieldSetter(ImmutableMultimap.class, "map"); 341 static final Serialization.FieldSetter<ImmutableMultimap> SIZE_FIELD_SETTER = 342 Serialization.getFieldSetter(ImmutableMultimap.class, "size"); 343 static final Serialization.FieldSetter<ImmutableSetMultimap> EMPTY_SET_FIELD_SETTER = 344 Serialization.getFieldSetter(ImmutableSetMultimap.class, "emptySet"); 345 } 346 347 ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map, int size) { 348 this.map = map; 349 this.size = size; 350 } 351 352 // mutators (not supported) 353 354 /** 355 * Guaranteed to throw an exception and leave the multimap unmodified. 356 * 357 * @throws UnsupportedOperationException always 358 * @deprecated Unsupported operation. 359 */ 360 @CanIgnoreReturnValue 361 @Deprecated 362 @Override 363 public ImmutableCollection<V> removeAll(Object key) { 364 throw new UnsupportedOperationException(); 365 } 366 367 /** 368 * Guaranteed to throw an exception and leave the multimap unmodified. 369 * 370 * @throws UnsupportedOperationException always 371 * @deprecated Unsupported operation. 372 */ 373 @CanIgnoreReturnValue 374 @Deprecated 375 @Override 376 public ImmutableCollection<V> replaceValues(K key, Iterable<? extends V> values) { 377 throw new UnsupportedOperationException(); 378 } 379 380 /** 381 * Guaranteed to throw an exception and leave the multimap unmodified. 382 * 383 * @throws UnsupportedOperationException always 384 * @deprecated Unsupported operation. 385 */ 386 @Deprecated 387 @Override 388 public void clear() { 389 throw new UnsupportedOperationException(); 390 } 391 392 /** 393 * Returns an immutable collection of the values for the given key. If no 394 * mappings in the multimap have the provided key, an empty immutable 395 * collection is returned. The values are in the same order as the parameters 396 * used to build this multimap. 397 */ 398 @Override 399 public abstract ImmutableCollection<V> get(K key); 400 401 /** 402 * Returns an immutable multimap which is the inverse of this one. For every 403 * key-value mapping in the original, the result will have a mapping with 404 * key and value reversed. 405 * 406 * @since 11.0 407 */ 408 public abstract ImmutableMultimap<V, K> inverse(); 409 410 /** 411 * Guaranteed to throw an exception and leave the multimap unmodified. 412 * 413 * @throws UnsupportedOperationException always 414 * @deprecated Unsupported operation. 415 */ 416 @CanIgnoreReturnValue 417 @Deprecated 418 @Override 419 public boolean put(K key, V value) { 420 throw new UnsupportedOperationException(); 421 } 422 423 /** 424 * Guaranteed to throw an exception and leave the multimap unmodified. 425 * 426 * @throws UnsupportedOperationException always 427 * @deprecated Unsupported operation. 428 */ 429 @CanIgnoreReturnValue 430 @Deprecated 431 @Override 432 public boolean putAll(K key, Iterable<? extends V> values) { 433 throw new UnsupportedOperationException(); 434 } 435 436 /** 437 * Guaranteed to throw an exception and leave the multimap unmodified. 438 * 439 * @throws UnsupportedOperationException always 440 * @deprecated Unsupported operation. 441 */ 442 @CanIgnoreReturnValue 443 @Deprecated 444 @Override 445 public boolean putAll(Multimap<? extends K, ? extends V> multimap) { 446 throw new UnsupportedOperationException(); 447 } 448 449 /** 450 * Guaranteed to throw an exception and leave the multimap unmodified. 451 * 452 * @throws UnsupportedOperationException always 453 * @deprecated Unsupported operation. 454 */ 455 @CanIgnoreReturnValue 456 @Deprecated 457 @Override 458 public boolean remove(Object key, Object value) { 459 throw new UnsupportedOperationException(); 460 } 461 462 /** 463 * Returns {@code true} if this immutable multimap's implementation contains references to 464 * user-created objects that aren't accessible via this multimap's methods. This is generally 465 * used to determine whether {@code copyOf} implementations should make an explicit copy to avoid 466 * memory leaks. 467 */ 468 boolean isPartialView() { 469 return map.isPartialView(); 470 } 471 472 // accessors 473 474 @Override 475 public boolean containsKey(@Nullable Object key) { 476 return map.containsKey(key); 477 } 478 479 @Override 480 public boolean containsValue(@Nullable Object value) { 481 return value != null && super.containsValue(value); 482 } 483 484 @Override 485 public int size() { 486 return size; 487 } 488 489 // views 490 491 /** 492 * Returns an immutable set of the distinct keys in this multimap, in the same 493 * order as they appear in this multimap. 494 */ 495 @Override 496 public ImmutableSet<K> keySet() { 497 return map.keySet(); 498 } 499 500 /** 501 * Returns an immutable map that associates each key with its corresponding 502 * values in the multimap. Keys and values appear in the same order as in this 503 * multimap. 504 */ 505 @Override 506 @SuppressWarnings("unchecked") // a widening cast 507 public ImmutableMap<K, Collection<V>> asMap() { 508 return (ImmutableMap) map; 509 } 510 511 @Override 512 Map<K, Collection<V>> createAsMap() { 513 throw new AssertionError("should never be called"); 514 } 515 516 /** 517 * Returns an immutable collection of all key-value pairs in the multimap. 518 */ 519 @Override 520 public ImmutableCollection<Entry<K, V>> entries() { 521 return (ImmutableCollection<Entry<K, V>>) super.entries(); 522 } 523 524 @Override 525 ImmutableCollection<Entry<K, V>> createEntries() { 526 return new EntryCollection<>(this); 527 } 528 529 private static class EntryCollection<K, V> extends ImmutableCollection<Entry<K, V>> { 530 @Weak final ImmutableMultimap<K, V> multimap; 531 532 EntryCollection(ImmutableMultimap<K, V> multimap) { 533 this.multimap = multimap; 534 } 535 536 @Override 537 public UnmodifiableIterator<Entry<K, V>> iterator() { 538 return multimap.entryIterator(); 539 } 540 541 @Override 542 boolean isPartialView() { 543 return multimap.isPartialView(); 544 } 545 546 @Override 547 public int size() { 548 return multimap.size(); 549 } 550 551 @Override 552 public boolean contains(Object object) { 553 if (object instanceof Entry) { 554 Entry<?, ?> entry = (Entry<?, ?>) object; 555 return multimap.containsEntry(entry.getKey(), entry.getValue()); 556 } 557 return false; 558 } 559 560 private static final long serialVersionUID = 0; 561 } 562 563 private abstract class Itr<T> extends UnmodifiableIterator<T> { 564 final Iterator<Entry<K, Collection<V>>> mapIterator = asMap().entrySet().iterator(); 565 K key = null; 566 Iterator<V> valueIterator = Iterators.emptyIterator(); 567 568 abstract T output(K key, V value); 569 570 @Override 571 public boolean hasNext() { 572 return mapIterator.hasNext() || valueIterator.hasNext(); 573 } 574 575 @Override 576 public T next() { 577 if (!valueIterator.hasNext()) { 578 Entry<K, Collection<V>> mapEntry = mapIterator.next(); 579 key = mapEntry.getKey(); 580 valueIterator = mapEntry.getValue().iterator(); 581 } 582 return output(key, valueIterator.next()); 583 } 584 } 585 586 @Override 587 UnmodifiableIterator<Entry<K, V>> entryIterator() { 588 return new Itr<Entry<K, V>>() { 589 @Override 590 Entry<K, V> output(K key, V value) { 591 return Maps.immutableEntry(key, value); 592 } 593 }; 594 } 595 596 /** 597 * Returns an immutable multiset containing all the keys in this multimap, in 598 * the same order and with the same frequencies as they appear in this 599 * multimap; to get only a single occurrence of each key, use {@link #keySet}. 600 */ 601 @Override 602 public ImmutableMultiset<K> keys() { 603 return (ImmutableMultiset<K>) super.keys(); 604 } 605 606 @Override 607 ImmutableMultiset<K> createKeys() { 608 return new Keys(); 609 } 610 611 @SuppressWarnings("serial") // Uses writeReplace, not default serialization 612 @WeakOuter 613 class Keys extends ImmutableMultiset<K> { 614 @Override 615 public boolean contains(@Nullable Object object) { 616 return containsKey(object); 617 } 618 619 @Override 620 public int count(@Nullable Object element) { 621 Collection<V> values = map.get(element); 622 return (values == null) ? 0 : values.size(); 623 } 624 625 @Override 626 public ImmutableSet<K> elementSet() { 627 return keySet(); 628 } 629 630 @Override 631 public int size() { 632 return ImmutableMultimap.this.size(); 633 } 634 635 @Override 636 Multiset.Entry<K> getEntry(int index) { 637 Map.Entry<K, ? extends Collection<V>> entry = map.entrySet().asList().get(index); 638 return Multisets.immutableEntry(entry.getKey(), entry.getValue().size()); 639 } 640 641 @Override 642 boolean isPartialView() { 643 return true; 644 } 645 } 646 647 /** 648 * Returns an immutable collection of the values in this multimap. Its 649 * iterator traverses the values for the first key, the values for the second 650 * key, and so on. 651 */ 652 @Override 653 public ImmutableCollection<V> values() { 654 return (ImmutableCollection<V>) super.values(); 655 } 656 657 @Override 658 ImmutableCollection<V> createValues() { 659 return new Values<>(this); 660 } 661 662 @Override 663 UnmodifiableIterator<V> valueIterator() { 664 return new Itr<V>() { 665 @Override 666 V output(K key, V value) { 667 return value; 668 } 669 }; 670 } 671 672 private static final class Values<K, V> extends ImmutableCollection<V> { 673 @Weak private final transient ImmutableMultimap<K, V> multimap; 674 675 Values(ImmutableMultimap<K, V> multimap) { 676 this.multimap = multimap; 677 } 678 679 @Override 680 public boolean contains(@Nullable Object object) { 681 return multimap.containsValue(object); 682 } 683 684 @Override 685 public UnmodifiableIterator<V> iterator() { 686 return multimap.valueIterator(); 687 } 688 689 @GwtIncompatible // not present in emulated superclass 690 @Override 691 int copyIntoArray(Object[] dst, int offset) { 692 for (ImmutableCollection<V> valueCollection : multimap.map.values()) { 693 offset = valueCollection.copyIntoArray(dst, offset); 694 } 695 return offset; 696 } 697 698 @Override 699 public int size() { 700 return multimap.size(); 701 } 702 703 @Override 704 boolean isPartialView() { 705 return true; 706 } 707 708 private static final long serialVersionUID = 0; 709 } 710 711 private static final long serialVersionUID = 0; 712}