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