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 }