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