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