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