Coverage Summary for Class: ImmutableMultimap (com.google.common.collect)

Class Method, % Line, %
ImmutableMultimap 13.5% (5/37) 15.1% (8/53)
ImmutableMultimap$1 0% (0/3) 0% (0/11)
ImmutableMultimap$2 0% (0/3) 0% (0/7)
ImmutableMultimap$Builder 33.3% (4/12) 25% (13/52)
ImmutableMultimap$EntryCollection 0% (0/5) 0% (0/10)
ImmutableMultimap$FieldSettersHolder 0% (0/2) 0% (0/4)
ImmutableMultimap$Keys 0% (0/8) 0% (0/10)
ImmutableMultimap$KeysSerializedForm 0% (0/2) 0% (0/3)
ImmutableMultimap$Values 0% (0/6) 0% (0/11)
Total 11.5% (9/78) 13% (21/161)


1 /* 2  * Copyright (C) 2008 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); 5  * you may not use this file except in compliance with the License. 6  * You may obtain a copy of the License at 7  * 8  * http://www.apache.org/licenses/LICENSE-2.0 9  * 10  * Unless required by applicable law or agreed to in writing, software 11  * distributed under the License is distributed on an "AS IS" BASIS, 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13  * See the License for the specific language governing permissions and 14  * limitations under the License. 15  */ 16  17 package com.google.common.collect; 18  19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.collect.CollectPreconditions.checkEntryNotNull; 21  22 import com.google.common.annotations.Beta; 23 import com.google.common.annotations.GwtCompatible; 24 import com.google.common.annotations.GwtIncompatible; 25 import com.google.errorprone.annotations.CanIgnoreReturnValue; 26 import com.google.errorprone.annotations.DoNotMock; 27 import com.google.j2objc.annotations.Weak; 28 import com.google.j2objc.annotations.WeakOuter; 29 import java.io.Serializable; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.Collection; 33 import java.util.Comparator; 34 import java.util.Iterator; 35 import java.util.Map; 36 import java.util.Map.Entry; 37 import java.util.Set; 38 import java.util.Spliterator; 39 import java.util.function.BiConsumer; 40 import org.checkerframework.checker.nullness.qual.Nullable; 41  42 /** 43  * A {@link Multimap} whose contents will never change, with many other important properties 44  * detailed at {@link ImmutableCollection}. 45  * 46  * <p><b>Warning:</b> avoid <i>direct</i> usage of {@link ImmutableMultimap} as a type (as with 47  * {@link Multimap} itself). Prefer subtypes such as {@link ImmutableSetMultimap} or {@link 48  * ImmutableListMultimap}, which have well-defined {@link #equals} semantics, thus avoiding a common 49  * source of bugs and confusion. 50  * 51  * <p><b>Note:</b> every {@link ImmutableMultimap} offers an {@link #inverse} view, so there is no 52  * need for a distinct {@code ImmutableBiMultimap} type. 53  * 54  * <p><a id="iteration"></a> 55  * 56  * <p><b>Key-grouped iteration.</b> All view collections follow the same iteration order. In all 57  * current implementations, the iteration order always keeps multiple entries with the same key 58  * together. Any creation method that would customarily respect insertion order (such as {@link 59  * #copyOf(Multimap)}) instead preserves key-grouped order by inserting entries for an existing key 60  * immediately after the last entry having that key. 61  * 62  * <p>See the Guava User Guide article on <a href= 63  * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>. 64  * 65  * @author Jared Levy 66  * @since 2.0 67  */ 68 @GwtCompatible(emulated = true) 69 public abstract class ImmutableMultimap<K, V> extends BaseImmutableMultimap<K, V> 70  implements Serializable { 71  72  /** 73  * Returns an empty multimap. 74  * 75  * <p><b>Performance note:</b> the instance returned is a singleton. 76  */ 77  public static <K, V> ImmutableMultimap<K, V> of() { 78  return ImmutableListMultimap.of(); 79  } 80  81  /** Returns an immutable multimap containing a single entry. */ 82  public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1) { 83  return ImmutableListMultimap.of(k1, v1); 84  } 85  86  /** Returns an immutable multimap containing the given entries, in order. */ 87  public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2) { 88  return ImmutableListMultimap.of(k1, v1, k2, v2); 89  } 90  91  /** 92  * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion 93  * order described in the <a href="#iteration">class documentation</a>. 94  */ 95  public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 96  return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3); 97  } 98  99  /** 100  * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion 101  * order described in the <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 "key-grouped" insertion 109  * order described in the <a href="#iteration">class documentation</a>. 110  */ 111  public static <K, V> ImmutableMultimap<K, V> of( 112  K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 113  return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); 114  } 115  116  // looking for of() with > 5 entries? Use the builder instead. 117  118  /** 119  * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 120  * Builder} constructor. 121  */ 122  public static <K, V> Builder<K, V> builder() { 123  return new Builder<>(); 124  } 125  126  /** 127  * A builder for creating immutable multimap instances, especially {@code public static final} 128  * multimaps ("constant multimaps"). Example: 129  * 130  * <pre>{@code 131  * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP = 132  * new ImmutableMultimap.Builder<String, Integer>() 133  * .put("one", 1) 134  * .putAll("several", 1, 2, 3) 135  * .putAll("many", 1, 2, 3, 4, 5) 136  * .build(); 137  * }</pre> 138  * 139  * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build 140  * multiple multimaps in series. Each multimap contains the key-value mappings in the previously 141  * created multimaps. 142  * 143  * @since 2.0 144  */ 145  @DoNotMock 146  public static class Builder<K, V> { 147  Map<K, Collection<V>> builderMap; 148  @Nullable Comparator<? super K> keyComparator; 149  @Nullable Comparator<? super V> valueComparator; 150  151  /** 152  * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 153  * ImmutableMultimap#builder}. 154  */ 155  public Builder() { 156  this.builderMap = Platform.preservesInsertionOrderOnPutsMap(); 157  } 158  159  Collection<V> newMutableValueCollection() { 160  return new ArrayList<>(); 161  } 162  163  /** Adds a key-value mapping to the built multimap. */ 164  @CanIgnoreReturnValue 165  public Builder<K, V> put(K key, V value) { 166  checkEntryNotNull(key, value); 167  Collection<V> valueCollection = builderMap.get(key); 168  if (valueCollection == null) { 169  builderMap.put(key, valueCollection = newMutableValueCollection()); 170  } 171  valueCollection.add(value); 172  return this; 173  } 174  175  /** 176  * Adds an entry to the built multimap. 177  * 178  * @since 11.0 179  */ 180  @CanIgnoreReturnValue 181  public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 182  return put(entry.getKey(), entry.getValue()); 183  } 184  185  /** 186  * Adds entries to the built multimap. 187  * 188  * @since 19.0 189  */ 190  @CanIgnoreReturnValue 191  @Beta 192  public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) { 193  for (Entry<? extends K, ? extends V> entry : entries) { 194  put(entry); 195  } 196  return this; 197  } 198  199  /** 200  * Stores a collection of values with the same key in the built multimap. 201  * 202  * @throws NullPointerException if {@code key}, {@code values}, or any element in {@code values} 203  * is null. The builder is left in an invalid state. 204  */ 205  @CanIgnoreReturnValue 206  public Builder<K, V> putAll(K key, Iterable<? extends V> values) { 207  if (key == null) { 208  throw new NullPointerException("null key in entry: null=" + Iterables.toString(values)); 209  } 210  Collection<V> valueCollection = builderMap.get(key); 211  if (valueCollection != null) { 212  for (V value : values) { 213  checkEntryNotNull(key, value); 214  valueCollection.add(value); 215  } 216  return this; 217  } 218  Iterator<? extends V> valuesItr = values.iterator(); 219  if (!valuesItr.hasNext()) { 220  return this; 221  } 222  valueCollection = newMutableValueCollection(); 223  while (valuesItr.hasNext()) { 224  V value = valuesItr.next(); 225  checkEntryNotNull(key, value); 226  valueCollection.add(value); 227  } 228  builderMap.put(key, valueCollection); 229  return this; 230  } 231  232  /** 233  * Stores an array of values with the same key in the built multimap. 234  * 235  * @throws NullPointerException if the key or any value is null. The builder is left in an 236  * invalid state. 237  */ 238  @CanIgnoreReturnValue 239  public Builder<K, V> putAll(K key, V... values) { 240  return putAll(key, Arrays.asList(values)); 241  } 242  243  /** 244  * Stores another multimap's entries in the built multimap. The generated multimap's key and 245  * value orderings correspond to the iteration ordering of the {@code multimap.asMap()} view, 246  * with new keys and values following any existing keys and values. 247  * 248  * @throws NullPointerException if any key or value in {@code multimap} is null. The builder is 249  * left in an invalid state. 250  */ 251  @CanIgnoreReturnValue 252  public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) { 253  for (Entry<? extends K, ? extends Collection<? extends V>> entry : 254  multimap.asMap().entrySet()) { 255  putAll(entry.getKey(), entry.getValue()); 256  } 257  return this; 258  } 259  260  /** 261  * Specifies the ordering of the generated multimap's keys. 262  * 263  * @since 8.0 264  */ 265  @CanIgnoreReturnValue 266  public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) { 267  this.keyComparator = checkNotNull(keyComparator); 268  return this; 269  } 270  271  /** 272  * Specifies the ordering of the generated multimap's values for each key. 273  * 274  * @since 8.0 275  */ 276  @CanIgnoreReturnValue 277  public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) { 278  this.valueComparator = checkNotNull(valueComparator); 279  return this; 280  } 281  282  @CanIgnoreReturnValue 283  Builder<K, V> combine(Builder<K, V> other) { 284  for (Map.Entry<K, Collection<V>> entry : other.builderMap.entrySet()) { 285  putAll(entry.getKey(), entry.getValue()); 286  } 287  return this; 288  } 289  290  /** Returns a newly-created immutable multimap. */ 291  public ImmutableMultimap<K, V> build() { 292  Collection<Map.Entry<K, Collection<V>>> mapEntries = builderMap.entrySet(); 293  if (keyComparator != null) { 294  mapEntries = Ordering.from(keyComparator).<K>onKeys().immutableSortedCopy(mapEntries); 295  } 296  return ImmutableListMultimap.fromMapEntries(mapEntries, valueComparator); 297  } 298  } 299  300  /** 301  * Returns an immutable multimap containing the same mappings as {@code multimap}, in the 302  * "key-grouped" iteration order described in the class documentation. 303  * 304  * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 305  * safe to do so. The exact circumstances under which a copy will or will not be performed are 306  * undocumented and subject to change. 307  * 308  * @throws NullPointerException if any key or value in {@code multimap} is null 309  */ 310  public static <K, V> ImmutableMultimap<K, V> copyOf(Multimap<? extends K, ? extends V> multimap) { 311  if (multimap instanceof ImmutableMultimap) { 312  @SuppressWarnings("unchecked") // safe since multimap is not writable 313  ImmutableMultimap<K, V> kvMultimap = (ImmutableMultimap<K, V>) multimap; 314  if (!kvMultimap.isPartialView()) { 315  return kvMultimap; 316  } 317  } 318  return ImmutableListMultimap.copyOf(multimap); 319  } 320  321  /** 322  * Returns an immutable multimap containing the specified entries. The returned multimap iterates 323  * over keys in the order they were first encountered in the input, and the values for each key 324  * are iterated in the order they were encountered. 325  * 326  * @throws NullPointerException if any key, value, or entry is null 327  * @since 19.0 328  */ 329  @Beta 330  public static <K, V> ImmutableMultimap<K, V> copyOf( 331  Iterable<? extends Entry<? extends K, ? extends V>> entries) { 332  return ImmutableListMultimap.copyOf(entries); 333  } 334  335  final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map; 336  final transient int size; 337  338  // These constants allow the deserialization code to set final fields. This 339  // holder class makes sure they are not initialized unless an instance is 340  // deserialized. 341  @GwtIncompatible // java serialization is not supported 342  static class FieldSettersHolder { 343  static final Serialization.FieldSetter<ImmutableMultimap> MAP_FIELD_SETTER = 344  Serialization.getFieldSetter(ImmutableMultimap.class, "map"); 345  static final Serialization.FieldSetter<ImmutableMultimap> SIZE_FIELD_SETTER = 346  Serialization.getFieldSetter(ImmutableMultimap.class, "size"); 347  } 348  349  ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map, int size) { 350  this.map = map; 351  this.size = size; 352  } 353  354  // mutators (not supported) 355  356  /** 357  * Guaranteed to throw an exception and leave the multimap unmodified. 358  * 359  * @throws UnsupportedOperationException always 360  * @deprecated Unsupported operation. 361  */ 362  @CanIgnoreReturnValue 363  @Deprecated 364  @Override 365  public ImmutableCollection<V> removeAll(Object key) { 366  throw new UnsupportedOperationException(); 367  } 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  public ImmutableCollection<V> replaceValues(K key, Iterable<? extends V> values) { 379  throw new UnsupportedOperationException(); 380  } 381  382  /** 383  * Guaranteed to throw an exception and leave the multimap unmodified. 384  * 385  * @throws UnsupportedOperationException always 386  * @deprecated Unsupported operation. 387  */ 388  @Deprecated 389  @Override 390  public void clear() { 391  throw new UnsupportedOperationException(); 392  } 393  394  /** 395  * Returns an immutable collection of the values for the given key. If no mappings in the multimap 396  * have the provided key, an empty immutable collection is returned. The values are in the same 397  * order as the parameters used to build this multimap. 398  */ 399  @Override 400  public abstract ImmutableCollection<V> get(K key); 401  402  /** 403  * Returns an immutable multimap which is the inverse of this one. For every key-value mapping in 404  * the original, the result will have a mapping with 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 used 465  * 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 order as they 493  * appear in this multimap. 494  */ 495  @Override 496  public ImmutableSet<K> keySet() { 497  return map.keySet(); 498  } 499  500  @Override 501  Set<K> createKeySet() { 502  throw new AssertionError("unreachable"); 503  } 504  505  /** 506  * Returns an immutable map that associates each key with its corresponding values in the 507  * multimap. Keys and values appear in the same order as in this multimap. 508  */ 509  @Override 510  @SuppressWarnings("unchecked") // a widening cast 511  public ImmutableMap<K, Collection<V>> asMap() { 512  return (ImmutableMap) map; 513  } 514  515  @Override 516  Map<K, Collection<V>> createAsMap() { 517  throw new AssertionError("should never be called"); 518  } 519  520  /** Returns an immutable collection of all key-value pairs in the multimap. */ 521  @Override 522  public ImmutableCollection<Entry<K, V>> entries() { 523  return (ImmutableCollection<Entry<K, V>>) super.entries(); 524  } 525  526  @Override 527  ImmutableCollection<Entry<K, V>> createEntries() { 528  return new EntryCollection<>(this); 529  } 530  531  private static class EntryCollection<K, V> extends ImmutableCollection<Entry<K, V>> { 532  @Weak final ImmutableMultimap<K, V> multimap; 533  534  EntryCollection(ImmutableMultimap<K, V> multimap) { 535  this.multimap = multimap; 536  } 537  538  @Override 539  public UnmodifiableIterator<Entry<K, V>> iterator() { 540  return multimap.entryIterator(); 541  } 542  543  @Override 544  boolean isPartialView() { 545  return multimap.isPartialView(); 546  } 547  548  @Override 549  public int size() { 550  return multimap.size(); 551  } 552  553  @Override 554  public boolean contains(Object object) { 555  if (object instanceof Entry) { 556  Entry<?, ?> entry = (Entry<?, ?>) object; 557  return multimap.containsEntry(entry.getKey(), entry.getValue()); 558  } 559  return false; 560  } 561  562  private static final long serialVersionUID = 0; 563  } 564  565  @Override 566  UnmodifiableIterator<Entry<K, V>> entryIterator() { 567  return new UnmodifiableIterator<Entry<K, V>>() { 568  final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>> asMapItr = 569  map.entrySet().iterator(); 570  K currentKey = null; 571  Iterator<V> valueItr = Iterators.emptyIterator(); 572  573  @Override 574  public boolean hasNext() { 575  return valueItr.hasNext() || asMapItr.hasNext(); 576  } 577  578  @Override 579  public Entry<K, V> next() { 580  if (!valueItr.hasNext()) { 581  Entry<K, ? extends ImmutableCollection<V>> entry = asMapItr.next(); 582  currentKey = entry.getKey(); 583  valueItr = entry.getValue().iterator(); 584  } 585  return Maps.immutableEntry(currentKey, valueItr.next()); 586  } 587  }; 588  } 589  590  @Override 591  Spliterator<Entry<K, V>> entrySpliterator() { 592  return CollectSpliterators.flatMap( 593  asMap().entrySet().spliterator(), 594  keyToValueCollectionEntry -> { 595  K key = keyToValueCollectionEntry.getKey(); 596  Collection<V> valueCollection = keyToValueCollectionEntry.getValue(); 597  return CollectSpliterators.map( 598  valueCollection.spliterator(), (V value) -> Maps.immutableEntry(key, value)); 599  }, 600  Spliterator.SIZED | (this instanceof SetMultimap ? Spliterator.DISTINCT : 0), 601  size()); 602  } 603  604  @Override 605  public void forEach(BiConsumer<? super K, ? super V> action) { 606  checkNotNull(action); 607  asMap() 608  .forEach( 609  (key, valueCollection) -> valueCollection.forEach(value -> action.accept(key, value))); 610  } 611  612  /** 613  * Returns an immutable multiset containing all the keys in this multimap, in the same order and 614  * with the same frequencies as they appear in this multimap; to get only a single occurrence of 615  * each key, use {@link #keySet}. 616  */ 617  @Override 618  public ImmutableMultiset<K> keys() { 619  return (ImmutableMultiset<K>) super.keys(); 620  } 621  622  @Override 623  ImmutableMultiset<K> createKeys() { 624  return new Keys(); 625  } 626  627  @SuppressWarnings("serial") // Uses writeReplace, not default serialization 628  @WeakOuter 629  class Keys extends ImmutableMultiset<K> { 630  @Override 631  public boolean contains(@Nullable Object object) { 632  return containsKey(object); 633  } 634  635  @Override 636  public int count(@Nullable Object element) { 637  Collection<V> values = map.get(element); 638  return (values == null) ? 0 : values.size(); 639  } 640  641  @Override 642  public ImmutableSet<K> elementSet() { 643  return keySet(); 644  } 645  646  @Override 647  public int size() { 648  return ImmutableMultimap.this.size(); 649  } 650  651  @Override 652  Multiset.Entry<K> getEntry(int index) { 653  Map.Entry<K, ? extends Collection<V>> entry = map.entrySet().asList().get(index); 654  return Multisets.immutableEntry(entry.getKey(), entry.getValue().size()); 655  } 656  657  @Override 658  boolean isPartialView() { 659  return true; 660  } 661  662  @GwtIncompatible 663  @Override 664  Object writeReplace() { 665  return new KeysSerializedForm(ImmutableMultimap.this); 666  } 667  } 668  669  @GwtIncompatible 670  private static final class KeysSerializedForm implements Serializable { 671  final ImmutableMultimap<?, ?> multimap; 672  673  KeysSerializedForm(ImmutableMultimap<?, ?> multimap) { 674  this.multimap = multimap; 675  } 676  677  Object readResolve() { 678  return multimap.keys(); 679  } 680  } 681  682  /** 683  * Returns an immutable collection of the values in this multimap. Its iterator traverses the 684  * values for the first key, the values for the second key, and so on. 685  */ 686  @Override 687  public ImmutableCollection<V> values() { 688  return (ImmutableCollection<V>) super.values(); 689  } 690  691  @Override 692  ImmutableCollection<V> createValues() { 693  return new Values<>(this); 694  } 695  696  @Override 697  UnmodifiableIterator<V> valueIterator() { 698  return new UnmodifiableIterator<V>() { 699  Iterator<? extends ImmutableCollection<V>> valueCollectionItr = map.values().iterator(); 700  Iterator<V> valueItr = Iterators.emptyIterator(); 701  702  @Override 703  public boolean hasNext() { 704  return valueItr.hasNext() || valueCollectionItr.hasNext(); 705  } 706  707  @Override 708  public V next() { 709  if (!valueItr.hasNext()) { 710  valueItr = valueCollectionItr.next().iterator(); 711  } 712  return valueItr.next(); 713  } 714  }; 715  } 716  717  private static final class Values<K, V> extends ImmutableCollection<V> { 718  @Weak private final transient ImmutableMultimap<K, V> multimap; 719  720  Values(ImmutableMultimap<K, V> multimap) { 721  this.multimap = multimap; 722  } 723  724  @Override 725  public boolean contains(@Nullable Object object) { 726  return multimap.containsValue(object); 727  } 728  729  @Override 730  public UnmodifiableIterator<V> iterator() { 731  return multimap.valueIterator(); 732  } 733  734  @GwtIncompatible // not present in emulated superclass 735  @Override 736  int copyIntoArray(Object[] dst, int offset) { 737  for (ImmutableCollection<V> valueCollection : multimap.map.values()) { 738  offset = valueCollection.copyIntoArray(dst, offset); 739  } 740  return offset; 741  } 742  743  @Override 744  public int size() { 745  return multimap.size(); 746  } 747  748  @Override 749  boolean isPartialView() { 750  return true; 751  } 752  753  private static final long serialVersionUID = 0; 754  } 755  756  private static final long serialVersionUID = 0; 757 }