1/* 2 * Copyright (C) 2008 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.collect; 18 19import com.google.common.annotations.GwtCompatible; 20 21import java.util.Map; 22 23import javax.annotation.Nullable; 24 25/** 26 * An immutable {@link BiMap} with reliable user-specified iteration order. Does 27 * not permit null keys or values. An {@code ImmutableBiMap} and its inverse 28 * have the same iteration ordering. 29 * 30 * <p>An instance of {@code ImmutableBiMap} contains its own data and will 31 * <i>never</i> change. {@code ImmutableBiMap} is convenient for 32 * {@code public static final} maps ("constant maps") and also lets you easily 33 * make a "defensive copy" of a bimap provided to your class by a caller. 34 * 35 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as 36 * it has no public or protected constructors. Thus, instances of this class are 37 * guaranteed to be immutable. 38 * 39 * @author Jared Levy 40 * @since 2.0 (imported from Google Collections Library) 41 */ 42@GwtCompatible(serializable = true, emulated = true) 43public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V> 44 implements BiMap<K, V> { 45 46 private static final ImmutableBiMap<Object, Object> EMPTY_IMMUTABLE_BIMAP 47 = new EmptyBiMap(); 48 49 /** 50 * Returns the empty bimap. 51 */ 52 // Casting to any type is safe because the set will never hold any elements. 53 @SuppressWarnings("unchecked") 54 public static <K, V> ImmutableBiMap<K, V> of() { 55 return (ImmutableBiMap<K, V>) EMPTY_IMMUTABLE_BIMAP; 56 } 57 58 /** 59 * Returns an immutable bimap containing a single entry. 60 */ 61 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) { 62 return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1)); 63 } 64 65 /** 66 * Returns an immutable map containing the given entries, in order. 67 * 68 * @throws IllegalArgumentException if duplicate keys or values are added 69 */ 70 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) { 71 return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1, k2, v2)); 72 } 73 74 /** 75 * Returns an immutable map containing the given entries, in order. 76 * 77 * @throws IllegalArgumentException if duplicate keys or values are added 78 */ 79 public static <K, V> ImmutableBiMap<K, V> of( 80 K k1, V v1, K k2, V v2, K k3, V v3) { 81 return new RegularImmutableBiMap<K, V>(ImmutableMap.of( 82 k1, v1, k2, v2, k3, v3)); 83 } 84 85 /** 86 * Returns an immutable map containing the given entries, in order. 87 * 88 * @throws IllegalArgumentException if duplicate keys or values are added 89 */ 90 public static <K, V> ImmutableBiMap<K, V> of( 91 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 92 return new RegularImmutableBiMap<K, V>(ImmutableMap.of( 93 k1, v1, k2, v2, k3, v3, k4, v4)); 94 } 95 96 /** 97 * Returns an immutable map containing the given entries, in order. 98 * 99 * @throws IllegalArgumentException if duplicate keys or values are added 100 */ 101 public static <K, V> ImmutableBiMap<K, V> of( 102 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 103 return new RegularImmutableBiMap<K, V>(ImmutableMap.of( 104 k1, v1, k2, v2, k3, v3, k4, v4, k5, v5)); 105 } 106 107 // looking for of() with > 5 entries? Use the builder instead. 108 109 /** 110 * Returns a new builder. The generated builder is equivalent to the builder 111 * created by the {@link Builder} constructor. 112 */ 113 public static <K, V> Builder<K, V> builder() { 114 return new Builder<K, V>(); 115 } 116 117 /** 118 * A builder for creating immutable bimap instances, especially {@code public 119 * static final} bimaps ("constant bimaps"). Example: <pre> {@code 120 * 121 * static final ImmutableBiMap<String, Integer> WORD_TO_INT = 122 * new ImmutableBiMap.Builder<String, Integer>() 123 * .put("one", 1) 124 * .put("two", 2) 125 * .put("three", 3) 126 * .build();}</pre> 127 * 128 * For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods 129 * are even more convenient. 130 * 131 * <p>Builder instances can be reused - it is safe to call {@link #build} 132 * multiple times to build multiple bimaps in series. Each bimap is a superset 133 * of the bimaps created before it. 134 * 135 * @since 2.0 (imported from Google Collections Library) 136 */ 137 public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> { 138 139 /** 140 * Creates a new builder. The returned builder is equivalent to the builder 141 * generated by {@link ImmutableBiMap#builder}. 142 */ 143 public Builder() {} 144 145 /** 146 * Associates {@code key} with {@code value} in the built bimap. Duplicate 147 * keys or values are not allowed, and will cause {@link #build} to fail. 148 */ 149 @Override public Builder<K, V> put(K key, V value) { 150 super.put(key, value); 151 return this; 152 } 153 154 /** 155 * Associates all of the given map's keys and values in the built bimap. 156 * Duplicate keys or values are not allowed, and will cause {@link #build} 157 * to fail. 158 * 159 * @throws NullPointerException if any key or value in {@code map} is null 160 */ 161 @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 162 super.putAll(map); 163 return this; 164 } 165 166 /** 167 * Returns a newly-created immutable bimap. 168 * 169 * @throws IllegalArgumentException if duplicate keys or values were added 170 */ 171 @Override public ImmutableBiMap<K, V> build() { 172 ImmutableMap<K, V> map = super.build(); 173 if (map.isEmpty()) { 174 return of(); 175 } 176 return new RegularImmutableBiMap<K, V>(map); 177 } 178 } 179 180 /** 181 * Returns an immutable bimap containing the same entries as {@code map}. If 182 * {@code map} somehow contains entries with duplicate keys (for example, if 183 * it is a {@code SortedMap} whose comparator is not <i>consistent with 184 * equals</i>), the results of this method are undefined. 185 * 186 * <p>Despite the method name, this method attempts to avoid actually copying 187 * the data when it is safe to do so. The exact circumstances under which a 188 * copy will or will not be performed are undocumented and subject to change. 189 * 190 * @throws IllegalArgumentException if two keys have the same value 191 * @throws NullPointerException if any key or value in {@code map} is null 192 */ 193 public static <K, V> ImmutableBiMap<K, V> copyOf( 194 Map<? extends K, ? extends V> map) { 195 if (map instanceof ImmutableBiMap) { 196 @SuppressWarnings("unchecked") // safe since map is not writable 197 ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map; 198 // TODO(user): if we need to make a copy of a BiMap because the 199 // forward map is a view, don't make a copy of the non-view delegate map 200 if (!bimap.isPartialView()) { 201 return bimap; 202 } 203 } 204 205 if (map.isEmpty()) { 206 return of(); 207 } 208 209 ImmutableMap<K, V> immutableMap = ImmutableMap.copyOf(map); 210 return new RegularImmutableBiMap<K, V>(immutableMap); 211 } 212 213 ImmutableBiMap() {} 214 215 abstract ImmutableMap<K, V> delegate(); 216 217 /** 218 * {@inheritDoc} 219 * 220 * <p>The inverse of an {@code ImmutableBiMap} is another 221 * {@code ImmutableBiMap}. 222 */ 223 @Override 224 public abstract ImmutableBiMap<V, K> inverse(); 225 226 @Override public boolean containsKey(@Nullable Object key) { 227 return delegate().containsKey(key); 228 } 229 230 @Override public boolean containsValue(@Nullable Object value) { 231 return inverse().containsKey(value); 232 } 233 234 @Override public ImmutableSet<Entry<K, V>> entrySet() { 235 return delegate().entrySet(); 236 } 237 238 @Override public V get(@Nullable Object key) { 239 return delegate().get(key); 240 } 241 242 @Override public ImmutableSet<K> keySet() { 243 return delegate().keySet(); 244 } 245 246 /** 247 * Returns an immutable set of the values in this map. The values are in the 248 * same order as the parameters used to build this map. 249 */ 250 @Override public ImmutableSet<V> values() { 251 return inverse().keySet(); 252 } 253 254 /** 255 * Guaranteed to throw an exception and leave the bimap unmodified. 256 * 257 * @throws UnsupportedOperationException always 258 */ 259 @Override 260 public V forcePut(K key, V value) { 261 throw new UnsupportedOperationException(); 262 } 263 264 @Override public boolean isEmpty() { 265 return delegate().isEmpty(); 266 } 267 268 @Override 269 public int size() { 270 return delegate().size(); 271 } 272 273 @Override public boolean equals(@Nullable Object object) { 274 return object == this || delegate().equals(object); 275 } 276 277 @Override public int hashCode() { 278 return delegate().hashCode(); 279 } 280 281 @Override public String toString() { 282 return delegate().toString(); 283 } 284 285 /** Bimap with no mappings. */ 286 @SuppressWarnings("serial") // uses writeReplace(), not default serialization 287 static class EmptyBiMap extends ImmutableBiMap<Object, Object> { 288 @Override ImmutableMap<Object, Object> delegate() { 289 return ImmutableMap.of(); 290 } 291 @Override public ImmutableBiMap<Object, Object> inverse() { 292 return this; 293 } 294 @Override boolean isPartialView() { 295 return false; 296 } 297 Object readResolve() { 298 return EMPTY_IMMUTABLE_BIMAP; // preserve singleton property 299 } 300 } 301 302 /** 303 * Serialized type for all ImmutableBiMap instances. It captures the logical 304 * contents and they are reconstructed using public factory methods. This 305 * ensures that the implementation types remain as implementation details. 306 * 307 * Since the bimap is immutable, ImmutableBiMap doesn't require special logic 308 * for keeping the bimap and its inverse in sync during serialization, the way 309 * AbstractBiMap does. 310 */ 311 private static class SerializedForm extends ImmutableMap.SerializedForm { 312 SerializedForm(ImmutableBiMap<?, ?> bimap) { 313 super(bimap); 314 } 315 @Override Object readResolve() { 316 Builder<Object, Object> builder = new Builder<Object, Object>(); 317 return createMap(builder); 318 } 319 private static final long serialVersionUID = 0; 320 } 321 322 @Override Object writeReplace() { 323 return new SerializedForm(this); 324 } 325} 326