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.ArrayList;
036import java.util.Arrays;
037import java.util.Collection;
038import java.util.Comparator;
039import java.util.Iterator;
040import java.util.Map;
041import java.util.Map.Entry;
042import java.util.Set;
043import javax.annotation.CheckForNull;
044import org.checkerframework.checker.nullness.qual.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@GwtCompatible(emulated = true)
073@ElementTypesAreNonnullByDefault
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   * A builder for creating immutable multimap instances, especially {@code public static final}
133   * multimaps ("constant multimaps"). Example:
134   *
135   * <pre>{@code
136   * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
137   *     new ImmutableMultimap.Builder<String, Integer>()
138   *         .put("one", 1)
139   *         .putAll("several", 1, 2, 3)
140   *         .putAll("many", 1, 2, 3, 4, 5)
141   *         .build();
142   * }</pre>
143   *
144   * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build
145   * multiple multimaps in series. Each multimap contains the key-value mappings in the previously
146   * created multimaps.
147   *
148   * @since 2.0
149   */
150  @DoNotMock
151  public static class Builder<K, V> {
152    final Map<K, Collection<V>> builderMap;
153    @CheckForNull Comparator<? super K> keyComparator;
154    @CheckForNull Comparator<? super V> valueComparator;
155
156    /**
157     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
158     * ImmutableMultimap#builder}.
159     */
160    public Builder() {
161      this.builderMap = Platform.preservesInsertionOrderOnPutsMap();
162    }
163
164    Collection<V> newMutableValueCollection() {
165      return new ArrayList<>();
166    }
167
168    /** Adds a key-value mapping to the built multimap. */
169    @CanIgnoreReturnValue
170    public Builder<K, V> put(K key, V value) {
171      checkEntryNotNull(key, value);
172      Collection<V> valueCollection = builderMap.get(key);
173      if (valueCollection == null) {
174        builderMap.put(key, valueCollection = newMutableValueCollection());
175      }
176      valueCollection.add(value);
177      return this;
178    }
179
180    /**
181     * Adds an entry to the built multimap.
182     *
183     * @since 11.0
184     */
185    @CanIgnoreReturnValue
186    public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
187      return put(entry.getKey(), entry.getValue());
188    }
189
190    /**
191     * Adds entries to the built multimap.
192     *
193     * @since 19.0
194     */
195    @CanIgnoreReturnValue
196    public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) {
197      for (Entry<? extends K, ? extends V> entry : entries) {
198        put(entry);
199      }
200      return this;
201    }
202
203    /**
204     * Stores a collection of values with the same key in the built multimap.
205     *
206     * @throws NullPointerException if {@code key}, {@code values}, or any element in {@code values}
207     *     is null. The builder is left in an invalid state.
208     */
209    @CanIgnoreReturnValue
210    public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
211      if (key == null) {
212        throw new NullPointerException("null key in entry: null=" + Iterables.toString(values));
213      }
214      Collection<V> valueCollection = builderMap.get(key);
215      if (valueCollection != null) {
216        for (V value : values) {
217          checkEntryNotNull(key, value);
218          valueCollection.add(value);
219        }
220        return this;
221      }
222      Iterator<? extends V> valuesItr = values.iterator();
223      if (!valuesItr.hasNext()) {
224        return this;
225      }
226      valueCollection = newMutableValueCollection();
227      while (valuesItr.hasNext()) {
228        V value = valuesItr.next();
229        checkEntryNotNull(key, value);
230        valueCollection.add(value);
231      }
232      builderMap.put(key, valueCollection);
233      return this;
234    }
235
236    /**
237     * Stores an array of values with the same key in the built multimap.
238     *
239     * @throws NullPointerException if the key or any value is null. The builder is left in an
240     *     invalid state.
241     */
242    @CanIgnoreReturnValue
243    public Builder<K, V> putAll(K key, V... values) {
244      return putAll(key, Arrays.asList(values));
245    }
246
247    /**
248     * Stores another multimap's entries in the built multimap. The generated multimap's key and
249     * value orderings correspond to the iteration ordering of the {@code multimap.asMap()} view,
250     * with new keys and values following any existing keys and values.
251     *
252     * @throws NullPointerException if any key or value in {@code multimap} is null. The builder is
253     *     left in an invalid state.
254     */
255    @CanIgnoreReturnValue
256    public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) {
257      for (Entry<? extends K, ? extends Collection<? extends V>> entry :
258          multimap.asMap().entrySet()) {
259        putAll(entry.getKey(), entry.getValue());
260      }
261      return this;
262    }
263
264    /**
265     * Specifies the ordering of the generated multimap's keys.
266     *
267     * @since 8.0
268     */
269    @CanIgnoreReturnValue
270    public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
271      this.keyComparator = checkNotNull(keyComparator);
272      return this;
273    }
274
275    /**
276     * Specifies the ordering of the generated multimap's values for each key.
277     *
278     * @since 8.0
279     */
280    @CanIgnoreReturnValue
281    public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
282      this.valueComparator = checkNotNull(valueComparator);
283      return this;
284    }
285
286    @CanIgnoreReturnValue
287    Builder<K, V> combine(Builder<K, V> other) {
288      for (Map.Entry<K, Collection<V>> entry : other.builderMap.entrySet()) {
289        putAll(entry.getKey(), entry.getValue());
290      }
291      return this;
292    }
293
294    /** Returns a newly-created immutable multimap. */
295    public ImmutableMultimap<K, V> build() {
296      Collection<Map.Entry<K, Collection<V>>> mapEntries = builderMap.entrySet();
297      if (keyComparator != null) {
298        mapEntries = Ordering.from(keyComparator).<K>onKeys().immutableSortedCopy(mapEntries);
299      }
300      return ImmutableListMultimap.fromMapEntries(mapEntries, valueComparator);
301    }
302  }
303
304  /**
305   * Returns an immutable multimap containing the same mappings as {@code multimap}, in the
306   * "key-grouped" iteration order described in the class documentation.
307   *
308   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
309   * safe to do so. The exact circumstances under which a copy will or will not be performed are
310   * undocumented and subject to change.
311   *
312   * @throws NullPointerException if any key or value in {@code multimap} is null
313   */
314  public static <K, V> ImmutableMultimap<K, V> copyOf(Multimap<? extends K, ? extends V> multimap) {
315    if (multimap instanceof ImmutableMultimap) {
316      @SuppressWarnings("unchecked") // safe since multimap is not writable
317      ImmutableMultimap<K, V> kvMultimap = (ImmutableMultimap<K, V>) multimap;
318      if (!kvMultimap.isPartialView()) {
319        return kvMultimap;
320      }
321    }
322    return ImmutableListMultimap.copyOf(multimap);
323  }
324
325  /**
326   * Returns an immutable multimap containing the specified entries. The returned multimap iterates
327   * over keys in the order they were first encountered in the input, and the values for each key
328   * are iterated in the order they were encountered.
329   *
330   * @throws NullPointerException if any key, value, or entry is null
331   * @since 19.0
332   */
333  public static <K, V> ImmutableMultimap<K, V> copyOf(
334      Iterable<? extends Entry<? extends K, ? extends V>> entries) {
335    return ImmutableListMultimap.copyOf(entries);
336  }
337
338  final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map;
339  final transient int size;
340
341  // These constants allow the deserialization code to set final fields. This
342  // holder class makes sure they are not initialized unless an instance is
343  // deserialized.
344  @GwtIncompatible // java serialization is not supported
345  @J2ktIncompatible
346  static class FieldSettersHolder {
347    static final Serialization.FieldSetter<ImmutableMultimap> MAP_FIELD_SETTER =
348        Serialization.getFieldSetter(ImmutableMultimap.class, "map");
349    static final Serialization.FieldSetter<ImmutableMultimap> SIZE_FIELD_SETTER =
350        Serialization.getFieldSetter(ImmutableMultimap.class, "size");
351  }
352
353  ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map, int size) {
354    this.map = map;
355    this.size = size;
356  }
357
358  // mutators (not supported)
359
360  /**
361   * Guaranteed to throw an exception and leave the multimap unmodified.
362   *
363   * @throws UnsupportedOperationException always
364   * @deprecated Unsupported operation.
365   */
366  @CanIgnoreReturnValue
367  @Deprecated
368  @Override
369  @DoNotCall("Always throws UnsupportedOperationException")
370  // DoNotCall wants this to be final, but we want to override it to return more specific types.
371  // Inheritance is closed, and all subtypes are @DoNotCall, so this is safe to suppress.
372  @SuppressWarnings("DoNotCall")
373  public ImmutableCollection<V> removeAll(@CheckForNull Object key) {
374    throw new UnsupportedOperationException();
375  }
376
377  /**
378   * Guaranteed to throw an exception and leave the multimap unmodified.
379   *
380   * @throws UnsupportedOperationException always
381   * @deprecated Unsupported operation.
382   */
383  @CanIgnoreReturnValue
384  @Deprecated
385  @Override
386  @DoNotCall("Always throws UnsupportedOperationException")
387  // DoNotCall wants this to be final, but we want to override it to return more specific types.
388  // Inheritance is closed, and all subtypes are @DoNotCall, so this is safe to suppress.
389  @SuppressWarnings("DoNotCall")
390  public ImmutableCollection<V> replaceValues(K key, Iterable<? extends V> values) {
391    throw new UnsupportedOperationException();
392  }
393
394  /**
395   * Guaranteed to throw an exception and leave the multimap unmodified.
396   *
397   * @throws UnsupportedOperationException always
398   * @deprecated Unsupported operation.
399   */
400  @Deprecated
401  @Override
402  @DoNotCall("Always throws UnsupportedOperationException")
403  public final void clear() {
404    throw new UnsupportedOperationException();
405  }
406
407  /**
408   * Returns an immutable collection of the values for the given key. If no mappings in the multimap
409   * have the provided key, an empty immutable collection is returned. The values are in the same
410   * order as the parameters used to build this multimap.
411   */
412  @Override
413  public abstract ImmutableCollection<V> get(K key);
414
415  /**
416   * Returns an immutable multimap which is the inverse of this one. For every key-value mapping in
417   * the original, the result will have a mapping with key and value reversed.
418   *
419   * @since 11.0
420   */
421  public abstract ImmutableMultimap<V, K> inverse();
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  @DoNotCall("Always throws UnsupportedOperationException")
433  public final boolean put(K key, V value) {
434    throw new UnsupportedOperationException();
435  }
436
437  /**
438   * Guaranteed to throw an exception and leave the multimap unmodified.
439   *
440   * @throws UnsupportedOperationException always
441   * @deprecated Unsupported operation.
442   */
443  @CanIgnoreReturnValue
444  @Deprecated
445  @Override
446  @DoNotCall("Always throws UnsupportedOperationException")
447  public final boolean putAll(K key, Iterable<? extends V> values) {
448    throw new UnsupportedOperationException();
449  }
450
451  /**
452   * Guaranteed to throw an exception and leave the multimap unmodified.
453   *
454   * @throws UnsupportedOperationException always
455   * @deprecated Unsupported operation.
456   */
457  @CanIgnoreReturnValue
458  @Deprecated
459  @Override
460  @DoNotCall("Always throws UnsupportedOperationException")
461  public final boolean putAll(Multimap<? extends K, ? extends V> multimap) {
462    throw new UnsupportedOperationException();
463  }
464
465  /**
466   * Guaranteed to throw an exception and leave the multimap unmodified.
467   *
468   * @throws UnsupportedOperationException always
469   * @deprecated Unsupported operation.
470   */
471  @CanIgnoreReturnValue
472  @Deprecated
473  @Override
474  @DoNotCall("Always throws UnsupportedOperationException")
475  public final boolean remove(@CheckForNull Object key, @CheckForNull Object value) {
476    throw new UnsupportedOperationException();
477  }
478
479  /**
480   * Returns {@code true} if this immutable multimap's implementation contains references to
481   * user-created objects that aren't accessible via this multimap's methods. This is generally used
482   * to determine whether {@code copyOf} implementations should make an explicit copy to avoid
483   * memory leaks.
484   */
485  boolean isPartialView() {
486    return map.isPartialView();
487  }
488
489  // accessors
490
491  @Override
492  public boolean containsKey(@CheckForNull Object key) {
493    return map.containsKey(key);
494  }
495
496  @Override
497  public boolean containsValue(@CheckForNull Object value) {
498    return value != null && super.containsValue(value);
499  }
500
501  @Override
502  public int size() {
503    return size;
504  }
505
506  // views
507
508  /**
509   * Returns an immutable set of the distinct keys in this multimap, in the same order as they
510   * appear in this multimap.
511   */
512  @Override
513  public ImmutableSet<K> keySet() {
514    return map.keySet();
515  }
516
517  @Override
518  Set<K> createKeySet() {
519    throw new AssertionError("unreachable");
520  }
521
522  /**
523   * Returns an immutable map that associates each key with its corresponding values in the
524   * multimap. Keys and values appear in the same order as in this multimap.
525   */
526  @Override
527  @SuppressWarnings("unchecked") // a widening cast
528  public ImmutableMap<K, Collection<V>> asMap() {
529    return (ImmutableMap) map;
530  }
531
532  @Override
533  Map<K, Collection<V>> createAsMap() {
534    throw new AssertionError("should never be called");
535  }
536
537  /** Returns an immutable collection of all key-value pairs in the multimap. */
538  @Override
539  public ImmutableCollection<Entry<K, V>> entries() {
540    return (ImmutableCollection<Entry<K, V>>) super.entries();
541  }
542
543  @Override
544  ImmutableCollection<Entry<K, V>> createEntries() {
545    return new EntryCollection<>(this);
546  }
547
548  private static class EntryCollection<K, V> extends ImmutableCollection<Entry<K, V>> {
549    @Weak final ImmutableMultimap<K, V> multimap;
550
551    EntryCollection(ImmutableMultimap<K, V> multimap) {
552      this.multimap = multimap;
553    }
554
555    @Override
556    public UnmodifiableIterator<Entry<K, V>> iterator() {
557      return multimap.entryIterator();
558    }
559
560    @Override
561    boolean isPartialView() {
562      return multimap.isPartialView();
563    }
564
565    @Override
566    public int size() {
567      return multimap.size();
568    }
569
570    @Override
571    public boolean contains(@CheckForNull Object object) {
572      if (object instanceof Entry) {
573        Entry<?, ?> entry = (Entry<?, ?>) object;
574        return multimap.containsEntry(entry.getKey(), entry.getValue());
575      }
576      return false;
577    }
578
579    private static final long serialVersionUID = 0;
580  }
581
582  @Override
583  UnmodifiableIterator<Entry<K, V>> entryIterator() {
584    return new UnmodifiableIterator<Entry<K, V>>() {
585      final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>> asMapItr =
586          map.entrySet().iterator();
587      @CheckForNull K currentKey = null;
588      Iterator<V> valueItr = Iterators.emptyIterator();
589
590      @Override
591      public boolean hasNext() {
592        return valueItr.hasNext() || asMapItr.hasNext();
593      }
594
595      @Override
596      public Entry<K, V> next() {
597        if (!valueItr.hasNext()) {
598          Entry<K, ? extends ImmutableCollection<V>> entry = asMapItr.next();
599          currentKey = entry.getKey();
600          valueItr = entry.getValue().iterator();
601        }
602        /*
603         * requireNonNull is safe: The first call to this method always enters the !hasNext() case
604         * and populates currentKey, after which it's never cleared.
605         */
606        return immutableEntry(requireNonNull(currentKey), valueItr.next());
607      }
608    };
609  }
610
611  /**
612   * Returns an immutable multiset containing all the keys in this multimap, in the same order and
613   * with the same frequencies as they appear in this multimap; to get only a single occurrence of
614   * each key, use {@link #keySet}.
615   */
616  @Override
617  public ImmutableMultiset<K> keys() {
618    return (ImmutableMultiset<K>) super.keys();
619  }
620
621  @Override
622  ImmutableMultiset<K> createKeys() {
623    return new Keys();
624  }
625
626  @SuppressWarnings("serial") // Uses writeReplace, not default serialization
627  @WeakOuter
628  class Keys extends ImmutableMultiset<K> {
629    @Override
630    public boolean contains(@CheckForNull Object object) {
631      return containsKey(object);
632    }
633
634    @Override
635    public int count(@CheckForNull Object element) {
636      Collection<V> values = map.get(element);
637      return (values == null) ? 0 : values.size();
638    }
639
640    @Override
641    public ImmutableSet<K> elementSet() {
642      return keySet();
643    }
644
645    @Override
646    public int size() {
647      return ImmutableMultimap.this.size();
648    }
649
650    @Override
651    Multiset.Entry<K> getEntry(int index) {
652      Map.Entry<K, ? extends Collection<V>> entry = map.entrySet().asList().get(index);
653      return Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
654    }
655
656    @Override
657    boolean isPartialView() {
658      return true;
659    }
660
661    @GwtIncompatible
662    @J2ktIncompatible
663    @Override
664    Object writeReplace() {
665      return new KeysSerializedForm(ImmutableMultimap.this);
666    }
667
668    @GwtIncompatible
669    @J2ktIncompatible
670    private void readObject(ObjectInputStream stream) throws InvalidObjectException {
671      throw new InvalidObjectException("Use KeysSerializedForm");
672    }
673  }
674
675  @GwtIncompatible
676  @J2ktIncompatible
677  private static final class KeysSerializedForm implements Serializable {
678    final ImmutableMultimap<?, ?> multimap;
679
680    KeysSerializedForm(ImmutableMultimap<?, ?> multimap) {
681      this.multimap = multimap;
682    }
683
684    Object readResolve() {
685      return multimap.keys();
686    }
687  }
688
689  /**
690   * Returns an immutable collection of the values in this multimap. Its iterator traverses the
691   * values for the first key, the values for the second key, and so on.
692   */
693  @Override
694  public ImmutableCollection<V> values() {
695    return (ImmutableCollection<V>) super.values();
696  }
697
698  @Override
699  ImmutableCollection<V> createValues() {
700    return new Values<>(this);
701  }
702
703  @Override
704  UnmodifiableIterator<V> valueIterator() {
705    return new UnmodifiableIterator<V>() {
706      Iterator<? extends ImmutableCollection<V>> valueCollectionItr = map.values().iterator();
707      Iterator<V> valueItr = Iterators.emptyIterator();
708
709      @Override
710      public boolean hasNext() {
711        return valueItr.hasNext() || valueCollectionItr.hasNext();
712      }
713
714      @Override
715      public V next() {
716        if (!valueItr.hasNext()) {
717          valueItr = valueCollectionItr.next().iterator();
718        }
719        return valueItr.next();
720      }
721    };
722  }
723
724  private static final class Values<K, V> extends ImmutableCollection<V> {
725    @Weak private final transient ImmutableMultimap<K, V> multimap;
726
727    Values(ImmutableMultimap<K, V> multimap) {
728      this.multimap = multimap;
729    }
730
731    @Override
732    public boolean contains(@CheckForNull Object object) {
733      return multimap.containsValue(object);
734    }
735
736    @Override
737    public UnmodifiableIterator<V> iterator() {
738      return multimap.valueIterator();
739    }
740
741    @GwtIncompatible // not present in emulated superclass
742    @Override
743    int copyIntoArray(@Nullable Object[] dst, int offset) {
744      for (ImmutableCollection<V> valueCollection : multimap.map.values()) {
745        offset = valueCollection.copyIntoArray(dst, offset);
746      }
747      return offset;
748    }
749
750    @Override
751    public int size() {
752      return multimap.size();
753    }
754
755    @Override
756    boolean isPartialView() {
757      return true;
758    }
759
760    @J2ktIncompatible // serialization
761    private static final long serialVersionUID = 0;
762  }
763
764  @J2ktIncompatible // serialization
765  private static final long serialVersionUID = 0;
766}