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