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