001 /* 002 * Copyright (C) 2008 Google Inc. 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 017 package com.google.common.collect; 018 019 import com.google.common.annotations.GwtCompatible; 020 021 import java.util.Map; 022 023 import javax.annotation.Nullable; 024 025 /** 026 * An immutable {@link BiMap} with reliable user-specified iteration order. Does 027 * not permit null keys or values. An {@code ImmutableBiMap} and its inverse 028 * have the same iteration ordering. 029 * 030 * <p>An instance of {@code ImmutableBiMap} contains its own data and will 031 * <i>never</i> change. {@code ImmutableBiMap} is convenient for 032 * {@code public static final} maps ("constant maps") and also lets you easily 033 * make a "defensive copy" of a bimap provided to your class by a caller. 034 * 035 * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as 036 * it has no public or protected constructors. Thus, instances of this class are 037 * guaranteed to be immutable. 038 * 039 * @author Jared Levy 040 * @since 2 (imported from Google Collections Library) 041 */ 042 @GwtCompatible(serializable = true, emulated = true) 043 public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V> 044 implements BiMap<K, V> { 045 046 private static final ImmutableBiMap<Object, Object> EMPTY_IMMUTABLE_BIMAP 047 = new EmptyBiMap(); 048 049 /** 050 * Returns the empty bimap. 051 */ 052 // Casting to any type is safe because the set will never hold any elements. 053 @SuppressWarnings("unchecked") 054 public static <K, V> ImmutableBiMap<K, V> of() { 055 return (ImmutableBiMap<K, V>) EMPTY_IMMUTABLE_BIMAP; 056 } 057 058 /** 059 * Returns an immutable bimap containing a single entry. 060 */ 061 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) { 062 return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1)); 063 } 064 065 /** 066 * Returns an immutable map containing the given entries, in order. 067 * 068 * @throws IllegalArgumentException if duplicate keys or values are added 069 */ 070 public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) { 071 return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1, k2, v2)); 072 } 073 074 /** 075 * Returns an immutable map containing the given entries, in order. 076 * 077 * @throws IllegalArgumentException if duplicate keys or values are added 078 */ 079 public static <K, V> ImmutableBiMap<K, V> of( 080 K k1, V v1, K k2, V v2, K k3, V v3) { 081 return new RegularImmutableBiMap<K, V>(ImmutableMap.of( 082 k1, v1, k2, v2, k3, v3)); 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( 091 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 092 return new RegularImmutableBiMap<K, V>(ImmutableMap.of( 093 k1, v1, k2, v2, k3, v3, k4, v4)); 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( 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 public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> { 136 137 /** 138 * Creates a new builder. The returned builder is equivalent to the builder 139 * generated by {@link ImmutableBiMap#builder}. 140 */ 141 public Builder() {} 142 143 /** 144 * Associates {@code key} with {@code value} in the built bimap. Duplicate 145 * keys or values are not allowed, and will cause {@link #build} to fail. 146 */ 147 @Override public Builder<K, V> put(K key, V value) { 148 super.put(key, value); 149 return this; 150 } 151 152 /** 153 * Associates all of the given map's keys and values in the built bimap. 154 * Duplicate keys or values are not allowed, and will cause {@link #build} 155 * to fail. 156 * 157 * @throws NullPointerException if any key or value in {@code map} is null 158 */ 159 @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 160 super.putAll(map); 161 return this; 162 } 163 164 /** 165 * Returns a newly-created immutable bimap. 166 * 167 * @throws IllegalArgumentException if duplicate keys or values were added 168 */ 169 @Override public ImmutableBiMap<K, V> build() { 170 ImmutableMap<K, V> map = super.build(); 171 if (map.isEmpty()) { 172 return of(); 173 } 174 return new RegularImmutableBiMap<K, V>(map); 175 } 176 } 177 178 /** 179 * Returns an immutable bimap containing the same entries as {@code map}. If 180 * {@code map} somehow contains entries with duplicate keys (for example, if 181 * it is a {@code SortedMap} whose comparator is not <i>consistent with 182 * equals</i>), the results of this method are undefined. 183 * 184 * <p><b>Note:</b> If {@code map} is an {@code ImmutableBiMap}, the given map 185 * itself will be returned. 186 * 187 * @throws IllegalArgumentException if two keys have the same value 188 * @throws NullPointerException if any key or value in {@code map} is null 189 */ 190 public static <K, V> ImmutableBiMap<K, V> copyOf( 191 Map<? extends K, ? extends V> map) { 192 if (map instanceof ImmutableBiMap) { 193 @SuppressWarnings("unchecked") // safe since map is not writable 194 ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map; 195 return bimap; 196 } 197 198 if (map.isEmpty()) { 199 return of(); 200 } 201 202 ImmutableMap<K, V> immutableMap = ImmutableMap.copyOf(map); 203 return new RegularImmutableBiMap<K, V>(immutableMap); 204 } 205 206 ImmutableBiMap() {} 207 208 abstract ImmutableMap<K, V> delegate(); 209 210 /** 211 * {@inheritDoc} 212 * 213 * <p>The inverse of an {@code ImmutableBiMap} is another 214 * {@code ImmutableBiMap}. 215 */ 216 public abstract ImmutableBiMap<V, K> inverse(); 217 218 @Override public boolean containsKey(@Nullable Object key) { 219 return delegate().containsKey(key); 220 } 221 222 @Override public boolean containsValue(@Nullable Object value) { 223 return inverse().containsKey(value); 224 } 225 226 @Override public ImmutableSet<Entry<K, V>> entrySet() { 227 return delegate().entrySet(); 228 } 229 230 @Override public V get(@Nullable Object key) { 231 return delegate().get(key); 232 } 233 234 @Override public ImmutableSet<K> keySet() { 235 return delegate().keySet(); 236 } 237 238 /** 239 * Returns an immutable set of the values in this map. The values are in the 240 * same order as the parameters used to build this map. 241 */ 242 @Override public ImmutableSet<V> values() { 243 return inverse().keySet(); 244 } 245 246 /** 247 * Guaranteed to throw an exception and leave the bimap unmodified. 248 * 249 * @throws UnsupportedOperationException always 250 */ 251 public V forcePut(K key, V value) { 252 throw new UnsupportedOperationException(); 253 } 254 255 @Override public boolean isEmpty() { 256 return delegate().isEmpty(); 257 } 258 259 public int size() { 260 return delegate().size(); 261 } 262 263 @Override public boolean equals(@Nullable Object object) { 264 return object == this || delegate().equals(object); 265 } 266 267 @Override public int hashCode() { 268 return delegate().hashCode(); 269 } 270 271 @Override public String toString() { 272 return delegate().toString(); 273 } 274 275 /** Bimap with no mappings. */ 276 @SuppressWarnings("serial") // uses writeReplace(), not default serialization 277 static class EmptyBiMap extends ImmutableBiMap<Object, Object> { 278 @Override ImmutableMap<Object, Object> delegate() { 279 return ImmutableMap.of(); 280 } 281 @Override public ImmutableBiMap<Object, Object> inverse() { 282 return this; 283 } 284 Object readResolve() { 285 return EMPTY_IMMUTABLE_BIMAP; // preserve singleton property 286 } 287 } 288 289 /** 290 * Serialized type for all ImmutableBiMap instances. It captures the logical 291 * contents and they are reconstructed using public factory methods. This 292 * ensures that the implementation types remain as implementation details. 293 * 294 * Since the bimap is immutable, ImmutableBiMap doesn't require special logic 295 * for keeping the bimap and its inverse in sync during serialization, the way 296 * AbstractBiMap does. 297 */ 298 private static class SerializedForm extends ImmutableMap.SerializedForm { 299 SerializedForm(ImmutableBiMap<?, ?> bimap) { 300 super(bimap); 301 } 302 @Override Object readResolve() { 303 Builder<Object, Object> builder = new Builder<Object, Object>(); 304 return createMap(builder); 305 } 306 private static final long serialVersionUID = 0; 307 } 308 309 @Override Object writeReplace() { 310 return new SerializedForm(this); 311 } 312 }