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