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; 021 022import com.google.common.annotations.Beta; 023import com.google.common.annotations.GwtCompatible; 024import com.google.common.annotations.VisibleForTesting; 025import com.google.errorprone.annotations.CanIgnoreReturnValue; 026import java.util.Arrays; 027import java.util.Comparator; 028import java.util.Map; 029import java.util.function.Function; 030import java.util.stream.Collector; 031import java.util.stream.Collectors; 032 033/** 034 * A {@link BiMap} whose contents will never change, with many other important properties detailed 035 * at {@link ImmutableCollection}. 036 * 037 * @author Jared Levy 038 * @since 2.0 039 */ 040@GwtCompatible(serializable = true, emulated = true) 041public abstract class ImmutableBiMap<K, V> extends ImmutableBiMapFauxverideShim<K, V> 042 implements BiMap<K, V> { 043 044 /** 045 * Returns a {@link Collector} that accumulates elements into an {@code ImmutableBiMap} whose keys 046 * and values are the result of applying the provided mapping functions to the input elements. 047 * Entries appear in the result {@code ImmutableBiMap} in encounter order. 048 * 049 * <p>If the mapped keys or values contain duplicates (according to {@link Object#equals(Object)}, 050 * an {@code IllegalArgumentException} is thrown when the collection operation is performed. (This 051 * differs from the {@code Collector} returned by {@link Collectors#toMap(Function, Function)}, 052 * which throws an {@code IllegalStateException}.) 053 * 054 * @since 21.0 055 */ 056 @Beta 057 public static <T, K, V> Collector<T, ?, ImmutableBiMap<K, V>> toImmutableBiMap( 058 Function<? super T, ? extends K> keyFunction, 059 Function<? super T, ? extends V> valueFunction) { 060 return CollectCollectors.toImmutableBiMap(keyFunction, valueFunction); 061 } 062 063 /** Returns the empty bimap. */ 064 // Casting to any type is safe because the set will never hold any elements. 065 @SuppressWarnings("unchecked") 066 public static <K, V> ImmutableBiMap<K, V> of() { 067 return (ImmutableBiMap<K, V>) RegularImmutableBiMap.EMPTY; 068 } 069 070 /** Returns an immutable bimap containing a single entry. */ 071 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) { 072 return new SingletonImmutableBiMap<>(k1, v1); 073 } 074 075 /** 076 * Returns an immutable map containing the given entries, in order. 077 * 078 * @throws IllegalArgumentException if duplicate keys or values are added 079 */ 080 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) { 081 return RegularImmutableBiMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2)); 082 } 083 084 /** 085 * Returns an immutable map containing the given entries, in order. 086 * 087 * @throws IllegalArgumentException if duplicate keys or values are added 088 */ 089 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) { 090 return RegularImmutableBiMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); 091 } 092 093 /** 094 * Returns an immutable map containing the given entries, in order. 095 * 096 * @throws IllegalArgumentException if duplicate keys or values are added 097 */ 098 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 099 return RegularImmutableBiMap.fromEntries( 100 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); 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( 109 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 110 return RegularImmutableBiMap.fromEntries( 111 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); 112 } 113 114 // looking for of() with > 5 entries? Use the builder instead. 115 116 /** 117 * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 118 * Builder} constructor. 119 */ 120 public static <K, V> Builder<K, V> builder() { 121 return new Builder<>(); 122 } 123 124 /** 125 * Returns a new builder, expecting the specified number of entries to be added. 126 * 127 * <p>If {@code expectedSize} is exactly the number of entries added to the builder before {@link 128 * Builder#build} is called, the builder is likely to perform better than an unsized {@link 129 * #builder()} would have. 130 * 131 * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to, 132 * but not exactly, the number of entries added to the builder. 133 * 134 * @since 23.1 135 */ 136 @Beta 137 public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) { 138 checkNonnegative(expectedSize, "expectedSize"); 139 return new Builder<>(expectedSize); 140 } 141 142 /** 143 * A builder for creating immutable bimap instances, especially {@code public static final} bimaps 144 * ("constant bimaps"). Example: 145 * 146 * <pre>{@code 147 * static final ImmutableBiMap<String, Integer> WORD_TO_INT = 148 * new ImmutableBiMap.Builder<String, Integer>() 149 * .put("one", 1) 150 * .put("two", 2) 151 * .put("three", 3) 152 * .build(); 153 * }</pre> 154 * 155 * <p>For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods are even more 156 * convenient. 157 * 158 * <p>By default, a {@code Builder} will generate bimaps that iterate over entries in the order 159 * they were inserted into the builder. For example, in the above example, {@code 160 * WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the order {@code "one"=1, 161 * "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect the same order. If you 162 * want a different order, consider using {@link #orderEntriesByValue(Comparator)}, which changes 163 * this builder to sort entries by value. 164 * 165 * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build 166 * multiple bimaps in series. Each bimap is a superset of the bimaps created before it. 167 * 168 * @since 2.0 169 */ 170 public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> { 171 172 /** 173 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 174 * ImmutableBiMap#builder}. 175 */ 176 public Builder() {} 177 178 Builder(int size) { 179 super(size); 180 } 181 182 /** 183 * Associates {@code key} with {@code value} in the built bimap. Duplicate keys or values are 184 * not allowed, and will cause {@link #build} to fail. 185 */ 186 @CanIgnoreReturnValue 187 @Override 188 public Builder<K, V> put(K key, V value) { 189 super.put(key, value); 190 return this; 191 } 192 193 /** 194 * Adds the given {@code entry} to the bimap. Duplicate keys or values are not allowed, and will 195 * cause {@link #build} to fail. 196 * 197 * @since 19.0 198 */ 199 @CanIgnoreReturnValue 200 @Override 201 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 202 super.put(entry); 203 return this; 204 } 205 206 /** 207 * Associates all of the given map's keys and values in the built bimap. Duplicate keys or 208 * values are not allowed, and will cause {@link #build} to fail. 209 * 210 * @throws NullPointerException if any key or value in {@code map} is null 211 */ 212 @CanIgnoreReturnValue 213 @Override 214 public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 215 super.putAll(map); 216 return this; 217 } 218 219 /** 220 * Adds all of the given entries to the built bimap. Duplicate keys or values are not allowed, 221 * and will cause {@link #build} to fail. 222 * 223 * @throws NullPointerException if any key, value, or entry is null 224 * @since 19.0 225 */ 226 @CanIgnoreReturnValue 227 @Beta 228 @Override 229 public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) { 230 super.putAll(entries); 231 return this; 232 } 233 234 /** 235 * Configures this {@code Builder} to order entries by value according to the specified 236 * comparator. 237 * 238 * <p>The sort order is stable, that is, if two entries have values that compare as equivalent, 239 * the entry that was inserted first will be first in the built map's iteration order. 240 * 241 * @throws IllegalStateException if this method was already called 242 * @since 19.0 243 */ 244 @CanIgnoreReturnValue 245 @Beta 246 @Override 247 public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) { 248 super.orderEntriesByValue(valueComparator); 249 return this; 250 } 251 252 @Override 253 @CanIgnoreReturnValue 254 Builder<K, V> combine(ImmutableMap.Builder<K, V> builder) { 255 super.combine(builder); 256 return this; 257 } 258 259 /** 260 * Returns a newly-created immutable bimap. The iteration order of the returned bimap is the 261 * order in which entries were inserted into the builder, unless {@link #orderEntriesByValue} 262 * was called, in which case entries are sorted by value. 263 * 264 * @throws IllegalArgumentException if duplicate keys or values were added 265 */ 266 @Override 267 public ImmutableBiMap<K, V> build() { 268 switch (size) { 269 case 0: 270 return of(); 271 case 1: 272 return of(entries[0].getKey(), entries[0].getValue()); 273 default: 274 /* 275 * If entries is full, or if hash flooding is detected, then this implementation may end 276 * up using the entries array directly and writing over the entry objects with 277 * non-terminal entries, but this is safe; if this Builder is used further, it will grow 278 * the entries array (so it can't affect the original array), and future build() calls 279 * will always copy any entry objects that cannot be safely reused. 280 */ 281 if (valueComparator != null) { 282 if (entriesUsed) { 283 entries = Arrays.copyOf(entries, size); 284 } 285 Arrays.sort( 286 entries, 287 0, 288 size, 289 Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction())); 290 } 291 entriesUsed = true; 292 return RegularImmutableBiMap.fromEntryArray(size, entries); 293 } 294 } 295 296 @Override 297 @VisibleForTesting 298 ImmutableBiMap<K, V> buildJdkBacked() { 299 checkState( 300 valueComparator == null, 301 "buildJdkBacked is for tests only, doesn't support orderEntriesByValue"); 302 switch (size) { 303 case 0: 304 return of(); 305 case 1: 306 return of(entries[0].getKey(), entries[0].getValue()); 307 default: 308 entriesUsed = true; 309 return RegularImmutableBiMap.fromEntryArray(size, entries); 310 } 311 } 312 } 313 314 /** 315 * Returns an immutable bimap containing the same entries as {@code map}. If {@code map} somehow 316 * contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose 317 * comparator is not <i>consistent with equals</i>), the results of this method are undefined. 318 * 319 * <p>The returned {@code BiMap} iterates over entries in the same order as the {@code entrySet} 320 * of the original map. 321 * 322 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 323 * safe to do so. The exact circumstances under which a copy will or will not be performed are 324 * undocumented and subject to change. 325 * 326 * @throws IllegalArgumentException if two keys have the same value or two values have the same 327 * key 328 * @throws NullPointerException if any key or value in {@code map} is null 329 */ 330 public static <K, V> ImmutableBiMap<K, V> copyOf(Map<? extends K, ? extends V> map) { 331 if (map instanceof ImmutableBiMap) { 332 @SuppressWarnings("unchecked") // safe since map is not writable 333 ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map; 334 // TODO(lowasser): if we need to make a copy of a BiMap because the 335 // forward map is a view, don't make a copy of the non-view delegate map 336 if (!bimap.isPartialView()) { 337 return bimap; 338 } 339 } 340 return copyOf(map.entrySet()); 341 } 342 343 /** 344 * Returns an immutable bimap containing the given entries. The returned bimap iterates over 345 * entries in the same order as the original iterable. 346 * 347 * @throws IllegalArgumentException if two keys have the same value or two values have the same 348 * key 349 * @throws NullPointerException if any key, value, or entry is null 350 * @since 19.0 351 */ 352 @Beta 353 public static <K, V> ImmutableBiMap<K, V> copyOf( 354 Iterable<? extends Entry<? extends K, ? extends V>> entries) { 355 @SuppressWarnings("unchecked") // we'll only be using getKey and getValue, which are covariant 356 Entry<K, V>[] entryArray = (Entry<K, V>[]) Iterables.toArray(entries, EMPTY_ENTRY_ARRAY); 357 switch (entryArray.length) { 358 case 0: 359 return of(); 360 case 1: 361 Entry<K, V> entry = entryArray[0]; 362 return of(entry.getKey(), entry.getValue()); 363 default: 364 /* 365 * The current implementation will end up using entryArray directly, though it will write 366 * over the (arbitrary, potentially mutable) Entry objects actually stored in entryArray. 367 */ 368 return RegularImmutableBiMap.fromEntries(entryArray); 369 } 370 } 371 372 ImmutableBiMap() {} 373 374 /** 375 * {@inheritDoc} 376 * 377 * <p>The inverse of an {@code ImmutableBiMap} is another {@code ImmutableBiMap}. 378 */ 379 @Override 380 public abstract ImmutableBiMap<V, K> inverse(); 381 382 /** 383 * Returns an immutable set of the values in this map, in the same order they appear in {@link 384 * #entrySet}. 385 */ 386 @Override 387 public ImmutableSet<V> values() { 388 return inverse().keySet(); 389 } 390 391 @Override 392 final ImmutableSet<V> createValues() { 393 throw new AssertionError("should never be called"); 394 } 395 396 /** 397 * Guaranteed to throw an exception and leave the bimap unmodified. 398 * 399 * @throws UnsupportedOperationException always 400 * @deprecated Unsupported operation. 401 */ 402 @CanIgnoreReturnValue 403 @Deprecated 404 @Override 405 public V forcePut(K key, V value) { 406 throw new UnsupportedOperationException(); 407 } 408 409 /** 410 * Serialized type for all ImmutableBiMap instances. It captures the logical contents and they are 411 * reconstructed using public factory methods. This ensures that the implementation types remain 412 * as implementation details. 413 * 414 * <p>Since the bimap is immutable, ImmutableBiMap doesn't require special logic for keeping the 415 * bimap and its inverse in sync during serialization, the way AbstractBiMap does. 416 */ 417 private static class SerializedForm extends ImmutableMap.SerializedForm { 418 SerializedForm(ImmutableBiMap<?, ?> bimap) { 419 super(bimap); 420 } 421 422 @Override 423 Object readResolve() { 424 Builder<Object, Object> builder = new Builder<>(); 425 return createMap(builder); 426 } 427 428 private static final long serialVersionUID = 0; 429 } 430 431 @Override 432 Object writeReplace() { 433 return new SerializedForm(this); 434 } 435}