001/* 002 * Copyright (C) 2009 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.checkNonnegative; 021import static java.lang.Math.max; 022import static java.util.Arrays.asList; 023import static java.util.Objects.requireNonNull; 024 025import com.google.common.annotations.GwtCompatible; 026import com.google.common.annotations.GwtIncompatible; 027import com.google.common.annotations.J2ktIncompatible; 028import com.google.common.base.MoreObjects; 029import com.google.errorprone.annotations.CanIgnoreReturnValue; 030import com.google.errorprone.annotations.DoNotCall; 031import com.google.errorprone.annotations.concurrent.LazyInit; 032import com.google.j2objc.annotations.RetainedWith; 033import com.google.j2objc.annotations.Weak; 034import java.io.IOException; 035import java.io.InvalidObjectException; 036import java.io.ObjectInputStream; 037import java.io.ObjectOutputStream; 038import java.util.Collection; 039import java.util.Comparator; 040import java.util.Map; 041import java.util.Map.Entry; 042import java.util.Set; 043import java.util.function.Function; 044import java.util.stream.Collector; 045import java.util.stream.Stream; 046import org.checkerframework.checker.nullness.qual.Nullable; 047 048/** 049 * A {@link SetMultimap} whose contents will never change, with many other important properties 050 * detailed at {@link ImmutableCollection}. 051 * 052 * <p><b>Warning:</b> As in all {@link SetMultimap}s, do not modify either a key <i>or a value</i> 053 * of a {@code ImmutableSetMultimap} in a way that affects its {@link Object#equals} behavior. 054 * Undefined behavior and bugs will result. 055 * 056 * <p>See the Guava User Guide article on <a href= 057 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained">immutable collections</a>. 058 * 059 * @author Mike Ward 060 * @since 2.0 061 */ 062@GwtCompatible(serializable = true, emulated = true) 063public class ImmutableSetMultimap<K, V> extends ImmutableMultimap<K, V> 064 implements SetMultimap<K, V> { 065 /** 066 * Returns a {@link Collector} that accumulates elements into an {@code ImmutableSetMultimap} 067 * whose keys and values are the result of applying the provided mapping functions to the input 068 * elements. 069 * 070 * <p>For streams with defined encounter order (as defined in the Ordering section of the {@link 071 * java.util.stream} Javadoc), that order is preserved, but entries are <a 072 * href="ImmutableMultimap.html#iteration">grouped by key</a>. 073 * 074 * <p>Example: 075 * 076 * <pre>{@code 077 * static final Multimap<Character, String> FIRST_LETTER_MULTIMAP = 078 * Stream.of("banana", "apple", "carrot", "asparagus", "cherry") 079 * .collect(toImmutableSetMultimap(str -> str.charAt(0), str -> str.substring(1))); 080 * 081 * // is equivalent to 082 * 083 * static final Multimap<Character, String> FIRST_LETTER_MULTIMAP = 084 * new ImmutableSetMultimap.Builder<Character, String>() 085 * .put('b', "anana") 086 * .putAll('a', "pple", "sparagus") 087 * .putAll('c', "arrot", "herry") 088 * .build(); 089 * }</pre> 090 * 091 * @since 33.2.0 (available since 21.0 in guava-jre) 092 */ 093 @SuppressWarnings("Java7ApiChecker") 094 @IgnoreJRERequirement // Users will use this only if they're already using streams. 095 public static <T extends @Nullable Object, K, V> 096 Collector<T, ?, ImmutableSetMultimap<K, V>> toImmutableSetMultimap( 097 Function<? super T, ? extends K> keyFunction, 098 Function<? super T, ? extends V> valueFunction) { 099 return CollectCollectors.toImmutableSetMultimap(keyFunction, valueFunction); 100 } 101 102 /** 103 * Returns a {@code Collector} accumulating entries into an {@code ImmutableSetMultimap}. Each 104 * input element is mapped to a key and a stream of values, each of which are put into the 105 * resulting {@code Multimap}, in the encounter order of the stream and the encounter order of the 106 * streams of values. 107 * 108 * <p>Example: 109 * 110 * <pre>{@code 111 * static final ImmutableSetMultimap<Character, Character> FIRST_LETTER_MULTIMAP = 112 * Stream.of("banana", "apple", "carrot", "asparagus", "cherry") 113 * .collect( 114 * flatteningToImmutableSetMultimap( 115 * str -> str.charAt(0), 116 * str -> str.substring(1).chars().mapToObj(c -> (char) c)); 117 * 118 * // is equivalent to 119 * 120 * static final ImmutableSetMultimap<Character, Character> FIRST_LETTER_MULTIMAP = 121 * ImmutableSetMultimap.<Character, Character>builder() 122 * .putAll('b', Arrays.asList('a', 'n', 'a', 'n', 'a')) 123 * .putAll('a', Arrays.asList('p', 'p', 'l', 'e')) 124 * .putAll('c', Arrays.asList('a', 'r', 'r', 'o', 't')) 125 * .putAll('a', Arrays.asList('s', 'p', 'a', 'r', 'a', 'g', 'u', 's')) 126 * .putAll('c', Arrays.asList('h', 'e', 'r', 'r', 'y')) 127 * .build(); 128 * 129 * // after deduplication, the resulting multimap is equivalent to 130 * 131 * static final ImmutableSetMultimap<Character, Character> FIRST_LETTER_MULTIMAP = 132 * ImmutableSetMultimap.<Character, Character>builder() 133 * .putAll('b', Arrays.asList('a', 'n')) 134 * .putAll('a', Arrays.asList('p', 'l', 'e', 's', 'a', 'r', 'g', 'u')) 135 * .putAll('c', Arrays.asList('a', 'r', 'o', 't', 'h', 'e', 'y')) 136 * .build(); 137 * } 138 * }</pre> 139 * 140 * @since 33.2.0 (available since 21.0 in guava-jre) 141 */ 142 @SuppressWarnings("Java7ApiChecker") 143 @IgnoreJRERequirement // Users will use this only if they're already using streams. 144 public static <T extends @Nullable Object, K, V> 145 Collector<T, ?, ImmutableSetMultimap<K, V>> flatteningToImmutableSetMultimap( 146 Function<? super T, ? extends K> keyFunction, 147 Function<? super T, ? extends Stream<? extends V>> valuesFunction) { 148 return CollectCollectors.flatteningToImmutableSetMultimap(keyFunction, valuesFunction); 149 } 150 151 /** 152 * Returns the empty multimap. 153 * 154 * <p><b>Performance note:</b> the instance returned is a singleton. 155 */ 156 // Casting is safe because the multimap will never hold any elements. 157 @SuppressWarnings("unchecked") 158 public static <K, V> ImmutableSetMultimap<K, V> of() { 159 return (ImmutableSetMultimap<K, V>) EmptyImmutableSetMultimap.INSTANCE; 160 } 161 162 /** Returns an immutable multimap containing a single entry. */ 163 public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1) { 164 ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder(); 165 builder.put(k1, v1); 166 return builder.build(); 167 } 168 169 /** 170 * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of 171 * an entry (according to {@link Object#equals}) after the first are ignored. 172 */ 173 public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1, K k2, V v2) { 174 ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder(); 175 builder.put(k1, v1); 176 builder.put(k2, v2); 177 return builder.build(); 178 } 179 180 /** 181 * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of 182 * an entry (according to {@link Object#equals}) after the first are ignored. 183 */ 184 public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 185 ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder(); 186 builder.put(k1, v1); 187 builder.put(k2, v2); 188 builder.put(k3, v3); 189 return builder.build(); 190 } 191 192 /** 193 * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of 194 * an entry (according to {@link Object#equals}) after the first are ignored. 195 */ 196 public static <K, V> ImmutableSetMultimap<K, V> of( 197 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 198 ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder(); 199 builder.put(k1, v1); 200 builder.put(k2, v2); 201 builder.put(k3, v3); 202 builder.put(k4, v4); 203 return builder.build(); 204 } 205 206 /** 207 * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of 208 * an entry (according to {@link Object#equals}) after the first are ignored. 209 */ 210 public static <K, V> ImmutableSetMultimap<K, V> of( 211 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 212 ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder(); 213 builder.put(k1, v1); 214 builder.put(k2, v2); 215 builder.put(k3, v3); 216 builder.put(k4, v4); 217 builder.put(k5, v5); 218 return builder.build(); 219 } 220 221 // looking for of() with > 5 entries? Use the builder instead. 222 223 /** Returns a new {@link Builder}. */ 224 public static <K, V> Builder<K, V> builder() { 225 return new Builder<>(); 226 } 227 228 /** 229 * Returns a new builder with a hint for how many distinct keys are expected to be added. The 230 * generated builder is equivalent to that returned by {@link #builder}, but may perform better if 231 * {@code expectedKeys} is a good estimate. 232 * 233 * @throws IllegalArgumentException if {@code expectedKeys} is negative 234 * @since 33.3.0 235 */ 236 public static <K, V> Builder<K, V> builderWithExpectedKeys(int expectedKeys) { 237 checkNonnegative(expectedKeys, "expectedKeys"); 238 return new Builder<>(expectedKeys); 239 } 240 241 /** 242 * A builder for creating immutable {@code SetMultimap} instances, especially {@code public static 243 * final} multimaps ("constant multimaps"). Example: 244 * 245 * <pre>{@code 246 * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP = 247 * new ImmutableSetMultimap.Builder<String, Integer>() 248 * .put("one", 1) 249 * .putAll("several", 1, 2, 3) 250 * .putAll("many", 1, 2, 3, 4, 5) 251 * .build(); 252 * }</pre> 253 * 254 * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build 255 * multiple multimaps in series. Each multimap contains the key-value mappings in the previously 256 * created multimaps. 257 * 258 * @since 2.0 259 */ 260 public static final class Builder<K, V> extends ImmutableMultimap.Builder<K, V> { 261 /** 262 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 263 * ImmutableSetMultimap#builder}. 264 */ 265 public Builder() { 266 super(); 267 } 268 269 Builder(int expectedKeys) { 270 super(expectedKeys); 271 } 272 273 @Override 274 ImmutableCollection.Builder<V> newValueCollectionBuilderWithExpectedSize(int expectedSize) { 275 return (valueComparator == null) 276 ? ImmutableSet.builderWithExpectedSize(expectedSize) 277 : new ImmutableSortedSet.Builder<V>(valueComparator, expectedSize); 278 } 279 280 @Override 281 int expectedValueCollectionSize(int defaultExpectedValues, Iterable<?> values) { 282 // Only trust the size of `values` if it is a Set and therefore probably already deduplicated. 283 if (values instanceof Set<?>) { 284 Set<?> collection = (Set<?>) values; 285 return max(defaultExpectedValues, collection.size()); 286 } else { 287 return defaultExpectedValues; 288 } 289 } 290 291 /** 292 * {@inheritDoc} 293 * 294 * <p>Note that {@code expectedValuesPerKey} is taken to mean the expected number of 295 * <i>distinct</i> values per key. 296 * 297 * @since 33.3.0 298 */ 299 @CanIgnoreReturnValue 300 @Override 301 public Builder<K, V> expectedValuesPerKey(int expectedValuesPerKey) { 302 super.expectedValuesPerKey(expectedValuesPerKey); 303 return this; 304 } 305 306 /** Adds a key-value mapping to the built multimap if it is not already present. */ 307 @CanIgnoreReturnValue 308 @Override 309 public Builder<K, V> put(K key, V value) { 310 super.put(key, value); 311 return this; 312 } 313 314 /** 315 * Adds an entry to the built multimap if it is not already present. 316 * 317 * @since 11.0 318 */ 319 @CanIgnoreReturnValue 320 @Override 321 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 322 super.put(entry); 323 return this; 324 } 325 326 /** 327 * {@inheritDoc} 328 * 329 * @since 19.0 330 */ 331 @CanIgnoreReturnValue 332 @Override 333 public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) { 334 super.putAll(entries); 335 return this; 336 } 337 338 @CanIgnoreReturnValue 339 @Override 340 public Builder<K, V> putAll(K key, Iterable<? extends V> values) { 341 super.putAll(key, values); 342 return this; 343 } 344 345 @CanIgnoreReturnValue 346 @Override 347 public Builder<K, V> putAll(K key, V... values) { 348 return putAll(key, asList(values)); 349 } 350 351 @CanIgnoreReturnValue 352 @Override 353 public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) { 354 for (Entry<? extends K, ? extends Collection<? extends V>> entry : 355 multimap.asMap().entrySet()) { 356 putAll(entry.getKey(), entry.getValue()); 357 } 358 return this; 359 } 360 361 @CanIgnoreReturnValue 362 @Override 363 Builder<K, V> combine(ImmutableMultimap.Builder<K, V> other) { 364 super.combine(other); 365 return this; 366 } 367 368 /** 369 * {@inheritDoc} 370 * 371 * @since 8.0 372 */ 373 @CanIgnoreReturnValue 374 @Override 375 public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) { 376 super.orderKeysBy(keyComparator); 377 return this; 378 } 379 380 /** 381 * Specifies the ordering of the generated multimap's values for each key. 382 * 383 * <p>If this method is called, the sets returned by the {@code get()} method of the generated 384 * multimap and its {@link Multimap#asMap()} view are {@link ImmutableSortedSet} instances. 385 * However, serialization does not preserve that property, though it does maintain the key and 386 * value ordering. 387 * 388 * @since 8.0 389 */ 390 // TODO: Make serialization behavior consistent. 391 @CanIgnoreReturnValue 392 @Override 393 public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) { 394 super.orderValuesBy(valueComparator); 395 return this; 396 } 397 398 /** Returns a newly-created immutable set multimap. */ 399 @Override 400 public ImmutableSetMultimap<K, V> build() { 401 if (builderMap == null) { 402 return ImmutableSetMultimap.of(); 403 } 404 Collection<Map.Entry<K, ImmutableCollection.Builder<V>>> mapEntries = builderMap.entrySet(); 405 if (keyComparator != null) { 406 mapEntries = Ordering.from(keyComparator).<K>onKeys().immutableSortedCopy(mapEntries); 407 } 408 return fromMapBuilderEntries(mapEntries, valueComparator); 409 } 410 } 411 412 /** 413 * Returns an immutable set multimap containing the same mappings as {@code multimap}. The 414 * generated multimap's key and value orderings correspond to the iteration ordering of the {@code 415 * multimap.asMap()} view. Repeated occurrences of an entry in the multimap after the first are 416 * ignored. 417 * 418 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 419 * safe to do so. The exact circumstances under which a copy will or will not be performed are 420 * undocumented and subject to change. 421 * 422 * @throws NullPointerException if any key or value in {@code multimap} is null 423 */ 424 public static <K, V> ImmutableSetMultimap<K, V> copyOf( 425 Multimap<? extends K, ? extends V> multimap) { 426 return copyOf(multimap, null); 427 } 428 429 private static <K, V> ImmutableSetMultimap<K, V> copyOf( 430 Multimap<? extends K, ? extends V> multimap, 431 @Nullable Comparator<? super V> valueComparator) { 432 checkNotNull(multimap); // eager for GWT 433 if (multimap.isEmpty() && valueComparator == null) { 434 return of(); 435 } 436 437 if (multimap instanceof ImmutableSetMultimap) { 438 @SuppressWarnings("unchecked") // safe since multimap is not writable 439 ImmutableSetMultimap<K, V> kvMultimap = (ImmutableSetMultimap<K, V>) multimap; 440 if (!kvMultimap.isPartialView()) { 441 return kvMultimap; 442 } 443 } 444 445 return fromMapEntries(multimap.asMap().entrySet(), valueComparator); 446 } 447 448 /** 449 * Returns an immutable multimap containing the specified entries. The returned multimap iterates 450 * over keys in the order they were first encountered in the input, and the values for each key 451 * are iterated in the order they were encountered. If two values for the same key are {@linkplain 452 * Object#equals equal}, the first value encountered is used. 453 * 454 * @throws NullPointerException if any key, value, or entry is null 455 * @since 19.0 456 */ 457 public static <K, V> ImmutableSetMultimap<K, V> copyOf( 458 Iterable<? extends Entry<? extends K, ? extends V>> entries) { 459 return new Builder<K, V>().putAll(entries).build(); 460 } 461 462 /** Creates an ImmutableSetMultimap from an asMap.entrySet. */ 463 static <K, V> ImmutableSetMultimap<K, V> fromMapEntries( 464 Collection<? extends Map.Entry<? extends K, ? extends Collection<? extends V>>> mapEntries, 465 @Nullable Comparator<? super V> valueComparator) { 466 if (mapEntries.isEmpty()) { 467 return of(); 468 } 469 ImmutableMap.Builder<K, ImmutableSet<V>> builder = 470 new ImmutableMap.Builder<>(mapEntries.size()); 471 int size = 0; 472 473 for (Entry<? extends K, ? extends Collection<? extends V>> entry : mapEntries) { 474 K key = entry.getKey(); 475 Collection<? extends V> values = entry.getValue(); 476 ImmutableSet<V> set = valueSet(valueComparator, values); 477 if (!set.isEmpty()) { 478 builder.put(key, set); 479 size += set.size(); 480 } 481 } 482 483 return new ImmutableSetMultimap<>(builder.buildOrThrow(), size, valueComparator); 484 } 485 486 /** Creates an ImmutableSetMultimap from a map to builders. */ 487 static <K, V> ImmutableSetMultimap<K, V> fromMapBuilderEntries( 488 Collection<? extends Map.Entry<K, ImmutableCollection.Builder<V>>> mapEntries, 489 @Nullable Comparator<? super V> valueComparator) { 490 if (mapEntries.isEmpty()) { 491 return of(); 492 } 493 ImmutableMap.Builder<K, ImmutableSet<V>> builder = 494 new ImmutableMap.Builder<>(mapEntries.size()); 495 int size = 0; 496 497 for (Entry<K, ImmutableCollection.Builder<V>> entry : mapEntries) { 498 K key = entry.getKey(); 499 ImmutableSet.Builder<? extends V> values = (ImmutableSet.Builder<V>) entry.getValue(); 500 // If orderValuesBy got called at the very end, we may need to do the ImmutableSet to 501 // ImmutableSortedSet copy for each of these. 502 ImmutableSet<V> set = valueSet(valueComparator, values.build()); 503 if (!set.isEmpty()) { 504 builder.put(key, set); 505 size += set.size(); 506 } 507 } 508 509 return new ImmutableSetMultimap<>(builder.buildOrThrow(), size, valueComparator); 510 } 511 512 /** 513 * Returned by get() when a missing key is provided. Also holds the comparator, if any, used for 514 * values. 515 */ 516 private final transient ImmutableSet<V> emptySet; 517 518 ImmutableSetMultimap( 519 ImmutableMap<K, ImmutableSet<V>> map, 520 int size, 521 @Nullable Comparator<? super V> valueComparator) { 522 super(map, size); 523 this.emptySet = emptySet(valueComparator); 524 } 525 526 // views 527 528 /** 529 * Returns an immutable set of the values for the given key. If no mappings in the multimap have 530 * the provided key, an empty immutable set is returned. The values are in the same order as the 531 * parameters used to build this multimap. 532 */ 533 @Override 534 public ImmutableSet<V> get(K key) { 535 // This cast is safe as its type is known in constructor. 536 ImmutableSet<V> set = (ImmutableSet<V>) map.get(key); 537 return MoreObjects.firstNonNull(set, emptySet); 538 } 539 540 @LazyInit @RetainedWith private transient @Nullable ImmutableSetMultimap<V, K> inverse; 541 542 /** 543 * {@inheritDoc} 544 * 545 * <p>Because an inverse of a set multimap cannot contain multiple pairs with the same key and 546 * value, this method returns an {@code ImmutableSetMultimap} rather than the {@code 547 * ImmutableMultimap} specified in the {@code ImmutableMultimap} class. 548 */ 549 @Override 550 public ImmutableSetMultimap<V, K> inverse() { 551 ImmutableSetMultimap<V, K> result = inverse; 552 return (result == null) ? (inverse = invert()) : result; 553 } 554 555 private ImmutableSetMultimap<V, K> invert() { 556 Builder<V, K> builder = builder(); 557 for (Entry<K, V> entry : entries()) { 558 builder.put(entry.getValue(), entry.getKey()); 559 } 560 ImmutableSetMultimap<V, K> invertedMultimap = builder.build(); 561 invertedMultimap.inverse = this; 562 return invertedMultimap; 563 } 564 565 /** 566 * Guaranteed to throw an exception and leave the multimap unmodified. 567 * 568 * @throws UnsupportedOperationException always 569 * @deprecated Unsupported operation. 570 */ 571 @CanIgnoreReturnValue 572 @Deprecated 573 @Override 574 @DoNotCall("Always throws UnsupportedOperationException") 575 public final ImmutableSet<V> removeAll(@Nullable Object key) { 576 throw new UnsupportedOperationException(); 577 } 578 579 /** 580 * Guaranteed to throw an exception and leave the multimap unmodified. 581 * 582 * @throws UnsupportedOperationException always 583 * @deprecated Unsupported operation. 584 */ 585 @CanIgnoreReturnValue 586 @Deprecated 587 @Override 588 @DoNotCall("Always throws UnsupportedOperationException") 589 public final ImmutableSet<V> replaceValues(K key, Iterable<? extends V> values) { 590 throw new UnsupportedOperationException(); 591 } 592 593 @LazyInit @RetainedWith private transient @Nullable ImmutableSet<Entry<K, V>> entries; 594 595 /** 596 * Returns an immutable collection of all key-value pairs in the multimap. Its iterator traverses 597 * the values for the first key, the values for the second key, and so on. 598 */ 599 @Override 600 public ImmutableSet<Entry<K, V>> entries() { 601 ImmutableSet<Entry<K, V>> result = entries; 602 return result == null ? (entries = new EntrySet<>(this)) : result; 603 } 604 605 private static final class EntrySet<K, V> extends ImmutableSet<Entry<K, V>> { 606 @Weak private final transient ImmutableSetMultimap<K, V> multimap; 607 608 EntrySet(ImmutableSetMultimap<K, V> multimap) { 609 this.multimap = multimap; 610 } 611 612 @Override 613 public boolean contains(@Nullable Object object) { 614 if (object instanceof Entry) { 615 Entry<?, ?> entry = (Entry<?, ?>) object; 616 return multimap.containsEntry(entry.getKey(), entry.getValue()); 617 } 618 return false; 619 } 620 621 @Override 622 public int size() { 623 return multimap.size(); 624 } 625 626 @Override 627 public UnmodifiableIterator<Entry<K, V>> iterator() { 628 return multimap.entryIterator(); 629 } 630 631 @Override 632 boolean isPartialView() { 633 return false; 634 } 635 636 // redeclare to help optimizers with b/310253115 637 @SuppressWarnings("RedundantOverride") 638 @Override 639 @J2ktIncompatible // serialization 640 @GwtIncompatible // serialization 641 Object writeReplace() { 642 return super.writeReplace(); 643 } 644 } 645 646 private static <V> ImmutableSet<V> valueSet( 647 @Nullable Comparator<? super V> valueComparator, Collection<? extends V> values) { 648 return (valueComparator == null) 649 ? ImmutableSet.copyOf(values) 650 : ImmutableSortedSet.copyOf(valueComparator, values); 651 } 652 653 private static <V> ImmutableSet<V> emptySet(@Nullable Comparator<? super V> valueComparator) { 654 return (valueComparator == null) 655 ? ImmutableSet.<V>of() 656 : ImmutableSortedSet.<V>emptySet(valueComparator); 657 } 658 659 private static <V> ImmutableSet.Builder<V> valuesBuilder( 660 @Nullable Comparator<? super V> valueComparator) { 661 return (valueComparator == null) 662 ? new ImmutableSet.Builder<V>() 663 : new ImmutableSortedSet.Builder<V>(valueComparator); 664 } 665 666 /** 667 * @serialData number of distinct keys, and then for each distinct key: the key, the number of 668 * values for that key, and the key's values 669 */ 670 @GwtIncompatible // java.io.ObjectOutputStream 671 @J2ktIncompatible 672 private void writeObject(ObjectOutputStream stream) throws IOException { 673 stream.defaultWriteObject(); 674 stream.writeObject(valueComparator()); 675 Serialization.writeMultimap(this, stream); 676 } 677 678 @Nullable Comparator<? super V> valueComparator() { 679 return emptySet instanceof ImmutableSortedSet 680 ? ((ImmutableSortedSet<V>) emptySet).comparator() 681 : null; 682 } 683 684 @GwtIncompatible // java serialization 685 @J2ktIncompatible 686 private static final class SetFieldSettersHolder { 687 static final Serialization.FieldSetter<? super ImmutableSetMultimap<?, ?>> 688 EMPTY_SET_FIELD_SETTER = 689 Serialization.getFieldSetter(ImmutableSetMultimap.class, "emptySet"); 690 } 691 692 @GwtIncompatible // java.io.ObjectInputStream 693 @J2ktIncompatible 694 // Serialization type safety is at the caller's mercy. 695 @SuppressWarnings("unchecked") 696 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 697 stream.defaultReadObject(); 698 Comparator<Object> valueComparator = (Comparator<Object>) stream.readObject(); 699 int keyCount = stream.readInt(); 700 if (keyCount < 0) { 701 throw new InvalidObjectException("Invalid key count " + keyCount); 702 } 703 ImmutableMap.Builder<Object, ImmutableSet<Object>> builder = ImmutableMap.builder(); 704 int tmpSize = 0; 705 706 for (int i = 0; i < keyCount; i++) { 707 Object key = requireNonNull(stream.readObject()); 708 int valueCount = stream.readInt(); 709 if (valueCount <= 0) { 710 throw new InvalidObjectException("Invalid value count " + valueCount); 711 } 712 713 ImmutableSet.Builder<Object> valuesBuilder = valuesBuilder(valueComparator); 714 for (int j = 0; j < valueCount; j++) { 715 valuesBuilder.add(requireNonNull(stream.readObject())); 716 } 717 ImmutableSet<Object> valueSet = valuesBuilder.build(); 718 if (valueSet.size() != valueCount) { 719 throw new InvalidObjectException("Duplicate key-value pairs exist for key " + key); 720 } 721 builder.put(key, valueSet); 722 tmpSize += valueCount; 723 } 724 725 ImmutableMap<Object, ImmutableSet<Object>> tmpMap; 726 try { 727 tmpMap = builder.buildOrThrow(); 728 } catch (IllegalArgumentException e) { 729 throw (InvalidObjectException) new InvalidObjectException(e.getMessage()).initCause(e); 730 } 731 732 FieldSettersHolder.MAP_FIELD_SETTER.set(this, tmpMap); 733 FieldSettersHolder.SIZE_FIELD_SETTER.set(this, tmpSize); 734 SetFieldSettersHolder.EMPTY_SET_FIELD_SETTER.set(this, emptySet(valueComparator)); 735 } 736 737 @GwtIncompatible // not needed in emulated source. 738 @J2ktIncompatible 739 private static final long serialVersionUID = 0; 740}