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}