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