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.collect.CollectPreconditions.checkEntryNotNull; 020import static com.google.common.collect.CollectPreconditions.checkNonnegative; 021 022import com.google.common.annotations.GwtCompatible; 023import com.google.common.annotations.J2ktIncompatible; 024import com.google.errorprone.annotations.CanIgnoreReturnValue; 025import com.google.errorprone.annotations.DoNotCall; 026import java.io.InvalidObjectException; 027import java.io.ObjectInputStream; 028import java.util.Arrays; 029import java.util.Collection; 030import java.util.Comparator; 031import java.util.Map; 032import java.util.function.BinaryOperator; 033import java.util.function.Function; 034import java.util.stream.Collector; 035import java.util.stream.Collectors; 036import javax.annotation.CheckForNull; 037import org.checkerframework.checker.nullness.qual.Nullable; 038 039/** 040 * A {@link BiMap} whose contents will never change, with many other important properties detailed 041 * at {@link ImmutableCollection}. 042 * 043 * @author Jared Levy 044 * @since 2.0 045 */ 046@GwtCompatible(serializable = true, emulated = true) 047@ElementTypesAreNonnullByDefault 048public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V> implements BiMap<K, V> { 049 050 /** 051 * Returns a {@link Collector} that accumulates elements into an {@code ImmutableBiMap} whose keys 052 * and values are the result of applying the provided mapping functions to the input elements. 053 * Entries appear in the result {@code ImmutableBiMap} in encounter order. 054 * 055 * <p>If the mapped keys or values contain duplicates (according to {@link 056 * Object#equals(Object)}), an {@code IllegalArgumentException} is thrown when the collection 057 * operation is performed. (This differs from the {@code Collector} returned by {@link 058 * Collectors#toMap(Function, Function)}, which throws an {@code IllegalStateException}.) 059 * 060 * @since 33.2.0 (available since 21.0 in guava-jre) 061 */ 062 @SuppressWarnings("Java7ApiChecker") 063 @IgnoreJRERequirement // Users will use this only if they're already using streams. 064 public static <T extends @Nullable Object, K, V> 065 Collector<T, ?, ImmutableBiMap<K, V>> toImmutableBiMap( 066 Function<? super T, ? extends K> keyFunction, 067 Function<? super T, ? extends V> valueFunction) { 068 return CollectCollectors.toImmutableBiMap(keyFunction, valueFunction); 069 } 070 071 /** 072 * Returns the empty bimap. 073 * 074 * <p><b>Performance note:</b> the instance returned is a singleton. 075 */ 076 // Casting to any type is safe because the set will never hold any elements. 077 @SuppressWarnings("unchecked") 078 public static <K, V> ImmutableBiMap<K, V> of() { 079 return (ImmutableBiMap<K, V>) RegularImmutableBiMap.EMPTY; 080 } 081 082 /** Returns an immutable bimap containing a single entry. */ 083 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) { 084 checkEntryNotNull(k1, v1); 085 return new RegularImmutableBiMap<>(new Object[] {k1, v1}, 1); 086 } 087 088 /** 089 * Returns an immutable map containing the given entries, in order. 090 * 091 * @throws IllegalArgumentException if duplicate keys or values are added 092 */ 093 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) { 094 checkEntryNotNull(k1, v1); 095 checkEntryNotNull(k2, v2); 096 return new RegularImmutableBiMap<K, V>(new Object[] {k1, v1, k2, v2}, 2); 097 } 098 099 /** 100 * Returns an immutable map containing the given entries, in order. 101 * 102 * @throws IllegalArgumentException if duplicate keys or values are added 103 */ 104 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 105 checkEntryNotNull(k1, v1); 106 checkEntryNotNull(k2, v2); 107 checkEntryNotNull(k3, v3); 108 return new RegularImmutableBiMap<K, V>(new Object[] {k1, v1, k2, v2, k3, v3}, 3); 109 } 110 111 /** 112 * Returns an immutable map containing the given entries, in order. 113 * 114 * @throws IllegalArgumentException if duplicate keys or values are added 115 */ 116 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 117 checkEntryNotNull(k1, v1); 118 checkEntryNotNull(k2, v2); 119 checkEntryNotNull(k3, v3); 120 checkEntryNotNull(k4, v4); 121 return new RegularImmutableBiMap<K, V>(new Object[] {k1, v1, k2, v2, k3, v3, k4, v4}, 4); 122 } 123 124 /** 125 * Returns an immutable map containing the given entries, in order. 126 * 127 * @throws IllegalArgumentException if duplicate keys or values are added 128 */ 129 public static <K, V> ImmutableBiMap<K, V> of( 130 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 131 checkEntryNotNull(k1, v1); 132 checkEntryNotNull(k2, v2); 133 checkEntryNotNull(k3, v3); 134 checkEntryNotNull(k4, v4); 135 checkEntryNotNull(k5, v5); 136 return new RegularImmutableBiMap<K, V>( 137 new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5}, 5); 138 } 139 140 /** 141 * Returns an immutable map containing the given entries, in order. 142 * 143 * @throws IllegalArgumentException if duplicate keys or values are added 144 * @since 31.0 145 */ 146 public static <K, V> ImmutableBiMap<K, V> of( 147 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) { 148 checkEntryNotNull(k1, v1); 149 checkEntryNotNull(k2, v2); 150 checkEntryNotNull(k3, v3); 151 checkEntryNotNull(k4, v4); 152 checkEntryNotNull(k5, v5); 153 checkEntryNotNull(k6, v6); 154 return new RegularImmutableBiMap<K, V>( 155 new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6}, 6); 156 } 157 /** 158 * Returns an immutable map containing the given entries, in order. 159 * 160 * @throws IllegalArgumentException if duplicate keys or values are added 161 * @since 31.0 162 */ 163 public static <K, V> ImmutableBiMap<K, V> of( 164 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) { 165 checkEntryNotNull(k1, v1); 166 checkEntryNotNull(k2, v2); 167 checkEntryNotNull(k3, v3); 168 checkEntryNotNull(k4, v4); 169 checkEntryNotNull(k5, v5); 170 checkEntryNotNull(k6, v6); 171 checkEntryNotNull(k7, v7); 172 return new RegularImmutableBiMap<K, V>( 173 new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7}, 7); 174 } 175 /** 176 * Returns an immutable map containing the given entries, in order. 177 * 178 * @throws IllegalArgumentException if duplicate keys or values are added 179 * @since 31.0 180 */ 181 public static <K, V> ImmutableBiMap<K, V> of( 182 K k1, 183 V v1, 184 K k2, 185 V v2, 186 K k3, 187 V v3, 188 K k4, 189 V v4, 190 K k5, 191 V v5, 192 K k6, 193 V v6, 194 K k7, 195 V v7, 196 K k8, 197 V v8) { 198 checkEntryNotNull(k1, v1); 199 checkEntryNotNull(k2, v2); 200 checkEntryNotNull(k3, v3); 201 checkEntryNotNull(k4, v4); 202 checkEntryNotNull(k5, v5); 203 checkEntryNotNull(k6, v6); 204 checkEntryNotNull(k7, v7); 205 checkEntryNotNull(k8, v8); 206 return new RegularImmutableBiMap<K, V>( 207 new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8}, 8); 208 } 209 /** 210 * Returns an immutable map containing the given entries, in order. 211 * 212 * @throws IllegalArgumentException if duplicate keys or values are added 213 * @since 31.0 214 */ 215 public static <K, V> ImmutableBiMap<K, V> of( 216 K k1, 217 V v1, 218 K k2, 219 V v2, 220 K k3, 221 V v3, 222 K k4, 223 V v4, 224 K k5, 225 V v5, 226 K k6, 227 V v6, 228 K k7, 229 V v7, 230 K k8, 231 V v8, 232 K k9, 233 V v9) { 234 checkEntryNotNull(k1, v1); 235 checkEntryNotNull(k2, v2); 236 checkEntryNotNull(k3, v3); 237 checkEntryNotNull(k4, v4); 238 checkEntryNotNull(k5, v5); 239 checkEntryNotNull(k6, v6); 240 checkEntryNotNull(k7, v7); 241 checkEntryNotNull(k8, v8); 242 checkEntryNotNull(k9, v9); 243 return new RegularImmutableBiMap<K, V>( 244 new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9}, 9); 245 } 246 /** 247 * Returns an immutable map containing the given entries, in order. 248 * 249 * @throws IllegalArgumentException if duplicate keys or values are added 250 * @since 31.0 251 */ 252 public static <K, V> ImmutableBiMap<K, V> of( 253 K k1, 254 V v1, 255 K k2, 256 V v2, 257 K k3, 258 V v3, 259 K k4, 260 V v4, 261 K k5, 262 V v5, 263 K k6, 264 V v6, 265 K k7, 266 V v7, 267 K k8, 268 V v8, 269 K k9, 270 V v9, 271 K k10, 272 V v10) { 273 checkEntryNotNull(k1, v1); 274 checkEntryNotNull(k2, v2); 275 checkEntryNotNull(k3, v3); 276 checkEntryNotNull(k4, v4); 277 checkEntryNotNull(k5, v5); 278 checkEntryNotNull(k6, v6); 279 checkEntryNotNull(k7, v7); 280 checkEntryNotNull(k8, v8); 281 checkEntryNotNull(k9, v9); 282 checkEntryNotNull(k10, v10); 283 return new RegularImmutableBiMap<K, V>( 284 new Object[] { 285 k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10 286 }, 287 10); 288 } 289 290 // looking for of() with > 10 entries? Use the builder or ofEntries instead. 291 292 /** 293 * Returns an immutable map containing the given entries, in order. 294 * 295 * @throws IllegalArgumentException if duplicate keys or values are provided 296 * @since 31.0 297 */ 298 @SafeVarargs 299 public static <K, V> ImmutableBiMap<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) { 300 @SuppressWarnings("unchecked") // we will only ever read these 301 Entry<K, V>[] entries2 = (Entry<K, V>[]) entries; 302 return copyOf(Arrays.asList(entries2)); 303 } 304 305 /** 306 * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 307 * Builder} constructor. 308 */ 309 public static <K, V> Builder<K, V> builder() { 310 return new Builder<>(); 311 } 312 313 /** 314 * Returns a new builder, expecting the specified number of entries to be added. 315 * 316 * <p>If {@code expectedSize} is exactly the number of entries added to the builder before {@link 317 * Builder#build} is called, the builder is likely to perform better than an unsized {@link 318 * #builder()} would have. 319 * 320 * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to, 321 * but not exactly, the number of entries added to the builder. 322 * 323 * @since 23.1 324 */ 325 public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) { 326 checkNonnegative(expectedSize, "expectedSize"); 327 return new Builder<>(expectedSize); 328 } 329 330 /** 331 * A builder for creating immutable bimap instances, especially {@code public static final} bimaps 332 * ("constant bimaps"). Example: 333 * 334 * <pre>{@code 335 * static final ImmutableBiMap<String, Integer> WORD_TO_INT = 336 * new ImmutableBiMap.Builder<String, Integer>() 337 * .put("one", 1) 338 * .put("two", 2) 339 * .put("three", 3) 340 * .buildOrThrow(); 341 * }</pre> 342 * 343 * <p>For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods are even more 344 * convenient. 345 * 346 * <p>By default, a {@code Builder} will generate bimaps that iterate over entries in the order 347 * they were inserted into the builder. For example, in the above example, {@code 348 * WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the order {@code "one"=1, 349 * "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect the same order. If you 350 * want a different order, consider using {@link #orderEntriesByValue(Comparator)}, which changes 351 * this builder to sort entries by value. 352 * 353 * <p>Builder instances can be reused - it is safe to call {@link #buildOrThrow} multiple times to 354 * build multiple bimaps in series. Each bimap is a superset of the bimaps created before it. 355 * 356 * @since 2.0 357 */ 358 public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> { 359 /** 360 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 361 * ImmutableBiMap#builder}. 362 */ 363 public Builder() { 364 super(); 365 } 366 367 Builder(int size) { 368 super(size); 369 } 370 371 /** 372 * Associates {@code key} with {@code value} in the built bimap. Duplicate keys or values are 373 * not allowed, and will cause {@link #build} to fail. 374 */ 375 @CanIgnoreReturnValue 376 @Override 377 public Builder<K, V> put(K key, V value) { 378 super.put(key, value); 379 return this; 380 } 381 382 /** 383 * Adds the given {@code entry} to the bimap. Duplicate keys or values are not allowed, and will 384 * cause {@link #build} to fail. 385 * 386 * @since 19.0 387 */ 388 @CanIgnoreReturnValue 389 @Override 390 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 391 super.put(entry); 392 return this; 393 } 394 395 /** 396 * Associates all of the given map's keys and values in the built bimap. Duplicate keys or 397 * values are not allowed, and will cause {@link #build} to fail. 398 * 399 * @throws NullPointerException if any key or value in {@code map} is null 400 */ 401 @CanIgnoreReturnValue 402 @Override 403 public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 404 super.putAll(map); 405 return this; 406 } 407 408 /** 409 * Adds all of the given entries to the built bimap. Duplicate keys or values are not allowed, 410 * and will cause {@link #build} to fail. 411 * 412 * @throws NullPointerException if any key, value, or entry is null 413 * @since 19.0 414 */ 415 @CanIgnoreReturnValue 416 @Override 417 public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) { 418 super.putAll(entries); 419 return this; 420 } 421 422 /** 423 * Configures this {@code Builder} to order entries by value according to the specified 424 * comparator. 425 * 426 * <p>The sort order is stable, that is, if two entries have values that compare as equivalent, 427 * the entry that was inserted first will be first in the built map's iteration order. 428 * 429 * @throws IllegalStateException if this method was already called 430 * @since 19.0 431 */ 432 @CanIgnoreReturnValue 433 @Override 434 public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) { 435 super.orderEntriesByValue(valueComparator); 436 return this; 437 } 438 439 @Override 440 @CanIgnoreReturnValue 441 Builder<K, V> combine(ImmutableMap.Builder<K, V> builder) { 442 super.combine(builder); 443 return this; 444 } 445 446 /** 447 * Returns a newly-created immutable bimap. The iteration order of the returned bimap is the 448 * order in which entries were inserted into the builder, unless {@link #orderEntriesByValue} 449 * was called, in which case entries are sorted by value. 450 * 451 * <p>Prefer the equivalent method {@link #buildOrThrow()} to make it explicit that the method 452 * will throw an exception if there are duplicate keys or values. The {@code build()} method 453 * will soon be deprecated. 454 * 455 * @throws IllegalArgumentException if duplicate keys or values were added 456 */ 457 @Override 458 public ImmutableBiMap<K, V> build() { 459 return buildOrThrow(); 460 } 461 462 /** 463 * Returns a newly-created immutable bimap, or throws an exception if any key or value was added 464 * more than once. The iteration order of the returned bimap is the order in which entries were 465 * inserted into the builder, unless {@link #orderEntriesByValue} was called, in which case 466 * entries are sorted by value. 467 * 468 * @throws IllegalArgumentException if duplicate keys or values were added 469 * @since 31.0 470 */ 471 @Override 472 public ImmutableBiMap<K, V> buildOrThrow() { 473 if (size == 0) { 474 return of(); 475 } 476 if (valueComparator != null) { 477 if (entriesUsed) { 478 alternatingKeysAndValues = Arrays.copyOf(alternatingKeysAndValues, 2 * size); 479 } 480 sortEntries(alternatingKeysAndValues, size, valueComparator); 481 } 482 entriesUsed = true; 483 return new RegularImmutableBiMap<K, V>(alternatingKeysAndValues, size); 484 } 485 486 /** 487 * Throws {@link UnsupportedOperationException}. This method is inherited from {@link 488 * ImmutableMap.Builder}, but it does not make sense for bimaps. 489 * 490 * @throws UnsupportedOperationException always 491 * @deprecated This method does not make sense for bimaps and should not be called. 492 * @since 31.1 493 */ 494 @DoNotCall 495 @Deprecated 496 @Override 497 public ImmutableBiMap<K, V> buildKeepingLast() { 498 throw new UnsupportedOperationException("Not supported for bimaps"); 499 } 500 } 501 502 /** 503 * Returns an immutable bimap containing the same entries as {@code map}. If {@code map} somehow 504 * contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose 505 * comparator is not <i>consistent with equals</i>), the results of this method are undefined. 506 * 507 * <p>The returned {@code BiMap} iterates over entries in the same order as the {@code entrySet} 508 * of the original map. 509 * 510 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 511 * safe to do so. The exact circumstances under which a copy will or will not be performed are 512 * undocumented and subject to change. 513 * 514 * @throws IllegalArgumentException if two keys have the same value or two values have the same 515 * key 516 * @throws NullPointerException if any key or value in {@code map} is null 517 */ 518 public static <K, V> ImmutableBiMap<K, V> copyOf(Map<? extends K, ? extends V> map) { 519 if (map instanceof ImmutableBiMap) { 520 @SuppressWarnings("unchecked") // safe since map is not writable 521 ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map; 522 // TODO(lowasser): if we need to make a copy of a BiMap because the 523 // forward map is a view, don't make a copy of the non-view delegate map 524 if (!bimap.isPartialView()) { 525 return bimap; 526 } 527 } 528 return copyOf(map.entrySet()); 529 } 530 531 /** 532 * Returns an immutable bimap containing the given entries. The returned bimap iterates over 533 * entries in the same order as the original iterable. 534 * 535 * @throws IllegalArgumentException if two keys have the same value or two values have the same 536 * key 537 * @throws NullPointerException if any key, value, or entry is null 538 * @since 19.0 539 */ 540 public static <K, V> ImmutableBiMap<K, V> copyOf( 541 Iterable<? extends Entry<? extends K, ? extends V>> entries) { 542 int estimatedSize = 543 (entries instanceof Collection) 544 ? ((Collection<?>) entries).size() 545 : ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY; 546 return new Builder<K, V>(estimatedSize).putAll(entries).build(); 547 } 548 549 ImmutableBiMap() {} 550 551 /** 552 * {@inheritDoc} 553 * 554 * <p>The inverse of an {@code ImmutableBiMap} is another {@code ImmutableBiMap}. 555 */ 556 @Override 557 public abstract ImmutableBiMap<V, K> inverse(); 558 559 /** 560 * Returns an immutable set of the values in this map, in the same order they appear in {@link 561 * #entrySet}. 562 */ 563 @Override 564 public ImmutableSet<V> values() { 565 return inverse().keySet(); 566 } 567 568 @Override 569 final ImmutableSet<V> createValues() { 570 throw new AssertionError("should never be called"); 571 } 572 573 /** 574 * Guaranteed to throw an exception and leave the bimap unmodified. 575 * 576 * @throws UnsupportedOperationException always 577 * @deprecated Unsupported operation. 578 */ 579 @CanIgnoreReturnValue 580 @Deprecated 581 @Override 582 @DoNotCall("Always throws UnsupportedOperationException") 583 @CheckForNull 584 public final V forcePut(K key, V value) { 585 throw new UnsupportedOperationException(); 586 } 587 588 /** 589 * Serialized type for all ImmutableBiMap instances. It captures the logical contents and they are 590 * reconstructed using public factory methods. This ensures that the implementation types remain 591 * as implementation details. 592 * 593 * <p>Since the bimap is immutable, ImmutableBiMap doesn't require special logic for keeping the 594 * bimap and its inverse in sync during serialization, the way AbstractBiMap does. 595 */ 596 @J2ktIncompatible // serialization 597 private static class SerializedForm<K, V> extends ImmutableMap.SerializedForm<K, V> { 598 SerializedForm(ImmutableBiMap<K, V> bimap) { 599 super(bimap); 600 } 601 602 @Override 603 Builder<K, V> makeBuilder(int size) { 604 return new Builder<>(size); 605 } 606 607 private static final long serialVersionUID = 0; 608 } 609 610 @Override 611 @J2ktIncompatible // serialization 612 Object writeReplace() { 613 return new SerializedForm<>(this); 614 } 615 616 @J2ktIncompatible // serialization 617 private void readObject(ObjectInputStream stream) throws InvalidObjectException { 618 throw new InvalidObjectException("Use SerializedForm"); 619 } 620 621 /** 622 * Not supported. Use {@link #toImmutableBiMap} instead. This method exists only to hide {@link 623 * ImmutableMap#toImmutableMap(Function, Function)} from consumers of {@code ImmutableBiMap}. 624 * 625 * @throws UnsupportedOperationException always 626 * @deprecated Use {@link ImmutableBiMap#toImmutableBiMap}. 627 * @since 33.2.0 (available since 21.0 in guava-jre) 628 */ 629 @Deprecated 630 @DoNotCall("Use toImmutableBiMap") 631 @SuppressWarnings("Java7ApiChecker") 632 @IgnoreJRERequirement // Users will use this only if they're already using streams. 633 public static <T extends @Nullable Object, K, V> 634 Collector<T, ?, ImmutableMap<K, V>> toImmutableMap( 635 Function<? super T, ? extends K> keyFunction, 636 Function<? super T, ? extends V> valueFunction) { 637 throw new UnsupportedOperationException(); 638 } 639 640 /** 641 * Not supported. This method does not make sense for {@code BiMap}. This method exists only to 642 * hide {@link ImmutableMap#toImmutableMap(Function, Function, BinaryOperator)} from consumers of 643 * {@code ImmutableBiMap}. 644 * 645 * @throws UnsupportedOperationException always 646 * @deprecated 647 * @since 33.2.0 (available since 21.0 in guava-jre) 648 */ 649 @Deprecated 650 @DoNotCall("Use toImmutableBiMap") 651 @SuppressWarnings("Java7ApiChecker") 652 @IgnoreJRERequirement // Users will use this only if they're already using streams. 653 public static <T extends @Nullable Object, K, V> 654 Collector<T, ?, ImmutableMap<K, V>> toImmutableMap( 655 Function<? super T, ? extends K> keyFunction, 656 Function<? super T, ? extends V> valueFunction, 657 BinaryOperator<V> mergeFunction) { 658 throw new UnsupportedOperationException(); 659 } 660 661 private static final long serialVersionUID = 0xdecaf; 662}