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