1 /* 2 * Copyright (C) 2008 Google Inc. 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 17 package com.google.common.collect; 18 19 import com.google.common.annotations.GwtCompatible; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.collect.Iterables.getOnlyElement; 22 23 import java.io.Serializable; 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.Map; 27 28 import javax.annotation.Nullable; 29 30 /** 31 * An immutable, hash-based {@link Map} with reliable user-specified iteration 32 * order. Does not permit null keys or values. 33 * 34 * <p>Unlike {@link Collections#unmodifiableMap}, which is a <i>view</i> of a 35 * separate map which can still change, an instance of {@code ImmutableMap} 36 * contains its own data and will <i>never</i> change. {@code ImmutableMap} is 37 * convenient for {@code public static final} maps ("constant maps") and also 38 * lets you easily make a "defensive copy" of a map provided to your class by a 39 * caller. 40 * 41 * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as 42 * it has no public or protected constructors. Thus, instances of this class are 43 * guaranteed to be immutable. 44 * 45 * @see ImmutableList 46 * @see ImmutableSet 47 * @author Jesse Wilson 48 * @author Kevin Bourrillion 49 * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library) 50 */ 51 @GwtCompatible(serializable = true) 52 @SuppressWarnings("serial") // we're overriding default serialization 53 public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable { 54 /** 55 * Returns the empty map. This map behaves and performs comparably to 56 * {@link Collections#emptyMap}, and is preferable mainly for consistency 57 * and maintainability of your code. 58 */ 59 // Casting to any type is safe because the set will never hold any elements. 60 @SuppressWarnings("unchecked") of()61 public static <K, V> ImmutableMap<K, V> of() { 62 // BEGIN android-changed 63 return (ImmutableMap) EmptyImmutableMap.INSTANCE; 64 // END android-changed 65 } 66 67 /** 68 * Returns an immutable map containing a single entry. This map behaves and 69 * performs comparably to {@link Collections#singletonMap} but will not accept 70 * a null key or value. It is preferable mainly for consistency and 71 * maintainability of your code. 72 */ of(K k1, V v1)73 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) { 74 return new SingletonImmutableMap<K, V>( 75 checkNotNull(k1), checkNotNull(v1)); 76 } 77 78 /** 79 * Returns an immutable map containing the given entries, in order. 80 * 81 * @throws IllegalArgumentException if duplicate keys are provided 82 */ of(K k1, V v1, K k2, V v2)83 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) { 84 return new RegularImmutableMap<K, V>(entryOf(k1, v1), entryOf(k2, v2)); 85 } 86 87 /** 88 * Returns an immutable map containing the given entries, in order. 89 * 90 * @throws IllegalArgumentException if duplicate keys are provided 91 */ of( K k1, V v1, K k2, V v2, K k3, V v3)92 public static <K, V> ImmutableMap<K, V> of( 93 K k1, V v1, K k2, V v2, K k3, V v3) { 94 return new RegularImmutableMap<K, V>( 95 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); 96 } 97 98 /** 99 * Returns an immutable map containing the given entries, in order. 100 * 101 * @throws IllegalArgumentException if duplicate keys are provided 102 */ of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)103 public static <K, V> ImmutableMap<K, V> of( 104 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 105 return new RegularImmutableMap<K, V>( 106 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); 107 } 108 109 /** 110 * Returns an immutable map containing the given entries, in order. 111 * 112 * @throws IllegalArgumentException if duplicate keys are provided 113 */ of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)114 public static <K, V> ImmutableMap<K, V> of( 115 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 116 return new RegularImmutableMap<K, V>(entryOf(k1, v1), 117 entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); 118 } 119 120 // looking for of() with > 5 entries? Use the builder instead. 121 122 /** 123 * Returns a new builder. The generated builder is equivalent to the builder 124 * created by the {@link Builder} constructor. 125 */ builder()126 public static <K, V> Builder<K, V> builder() { 127 return new Builder<K, V>(); 128 } 129 130 /** 131 * Verifies that {@code key} and {@code value} are non-null, and returns a new 132 * immutable entry with those values. 133 * 134 * <p>A call to {@link Map.Entry#setValue} on the returned entry will always 135 * throw {@link UnsupportedOperationException}. 136 */ entryOf(K key, V value)137 static <K, V> Entry<K, V> entryOf(K key, V value) { 138 return Maps.immutableEntry(checkNotNull(key), checkNotNull(value)); 139 } 140 141 /** 142 * A builder for creating immutable map instances, especially {@code public 143 * static final} maps ("constant maps"). Example: <pre> {@code 144 * 145 * static final ImmutableMap<String, Integer> WORD_TO_INT = 146 * new ImmutableMap.Builder<String, Integer>() 147 * .put("one", 1) 148 * .put("two", 2) 149 * .put("three", 3) 150 * .build();}</pre> 151 * 152 * For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are 153 * even more convenient. 154 * 155 * <p>Builder instances can be reused - it is safe to call {@link #build} 156 * multiple times to build multiple maps in series. Each map is a superset of 157 * the maps created before it. 158 */ 159 public static class Builder<K, V> { 160 final List<Entry<K, V>> entries = Lists.newArrayList(); 161 162 /** 163 * Creates a new builder. The returned builder is equivalent to the builder 164 * generated by {@link ImmutableMap#builder}. 165 */ Builder()166 public Builder() {} 167 168 /** 169 * Associates {@code key} with {@code value} in the built map. Duplicate 170 * keys are not allowed, and will cause {@link #build} to fail. 171 */ put(K key, V value)172 public Builder<K, V> put(K key, V value) { 173 entries.add(entryOf(key, value)); 174 return this; 175 } 176 177 /** 178 * Associates all of the given map's keys and values in the built map. 179 * Duplicate keys are not allowed, and will cause {@link #build} to fail. 180 * 181 * @throws NullPointerException if any key or value in {@code map} is null 182 */ putAll(Map<? extends K, ? extends V> map)183 public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 184 for (Entry<? extends K, ? extends V> entry : map.entrySet()) { 185 put(entry.getKey(), entry.getValue()); 186 } 187 return this; 188 } 189 190 // TODO: Should build() and the ImmutableBiMap & ImmutableSortedMap versions 191 // throw an IllegalStateException instead? 192 193 /** 194 * Returns a newly-created immutable map. 195 * 196 * @throws IllegalArgumentException if duplicate keys were added 197 */ build()198 public ImmutableMap<K, V> build() { 199 return fromEntryList(entries); 200 } 201 fromEntryList( List<Entry<K, V>> entries)202 private static <K, V> ImmutableMap<K, V> fromEntryList( 203 List<Entry<K, V>> entries) { 204 int size = entries.size(); 205 switch (size) { 206 case 0: 207 return of(); 208 case 1: 209 return new SingletonImmutableMap<K, V>(getOnlyElement(entries)); 210 default: 211 Entry<?, ?>[] entryArray 212 = entries.toArray(new Entry<?, ?>[entries.size()]); 213 return new RegularImmutableMap<K, V>(entryArray); 214 } 215 } 216 } 217 218 /** 219 * Returns an immutable map containing the same entries as {@code map}. If 220 * {@code map} somehow contains entries with duplicate keys (for example, if 221 * it is a {@code SortedMap} whose comparator is not <i>consistent with 222 * equals</i>), the results of this method are undefined. 223 * 224 * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is an 225 * {@code ImmutableMap}, no copy will actually be performed, and the given map 226 * itself will be returned. 227 * 228 * @throws NullPointerException if any key or value in {@code map} is null 229 */ copyOf( Map<? extends K, ? extends V> map)230 public static <K, V> ImmutableMap<K, V> copyOf( 231 Map<? extends K, ? extends V> map) { 232 if ((map instanceof ImmutableMap) && !(map instanceof ImmutableSortedMap)) { 233 @SuppressWarnings("unchecked") // safe since map is not writable 234 ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map; 235 return kvMap; 236 } 237 238 @SuppressWarnings("unchecked") // we won't write to this array 239 Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]); 240 switch (entries.length) { 241 case 0: 242 return of(); 243 case 1: 244 return new SingletonImmutableMap<K, V>(entryOf( 245 entries[0].getKey(), entries[0].getValue())); 246 default: 247 for (int i = 0; i < entries.length; i++) { 248 K k = entries[i].getKey(); 249 V v = entries[i].getValue(); 250 entries[i] = entryOf(k, v); 251 } 252 return new RegularImmutableMap<K, V>(entries); 253 } 254 } 255 ImmutableMap()256 ImmutableMap() {} 257 258 /** 259 * Guaranteed to throw an exception and leave the map unmodified. 260 * 261 * @throws UnsupportedOperationException always 262 */ put(K k, V v)263 public final V put(K k, V v) { 264 throw new UnsupportedOperationException(); 265 } 266 267 /** 268 * Guaranteed to throw an exception and leave the map unmodified. 269 * 270 * @throws UnsupportedOperationException always 271 */ remove(Object o)272 public final V remove(Object o) { 273 throw new UnsupportedOperationException(); 274 } 275 276 /** 277 * Guaranteed to throw an exception and leave the map unmodified. 278 * 279 * @throws UnsupportedOperationException always 280 */ putAll(Map<? extends K, ? extends V> map)281 public final void putAll(Map<? extends K, ? extends V> map) { 282 throw new UnsupportedOperationException(); 283 } 284 285 /** 286 * Guaranteed to throw an exception and leave the map unmodified. 287 * 288 * @throws UnsupportedOperationException always 289 */ clear()290 public final void clear() { 291 throw new UnsupportedOperationException(); 292 } 293 isEmpty()294 public boolean isEmpty() { 295 return size() == 0; 296 } 297 containsKey(@ullable Object key)298 public boolean containsKey(@Nullable Object key) { 299 return get(key) != null; 300 } 301 302 // Overriding to mark it Nullable containsValue(@ullable Object value)303 public abstract boolean containsValue(@Nullable Object value); 304 305 // Overriding to mark it Nullable get(@ullable Object key)306 public abstract V get(@Nullable Object key); 307 308 /** 309 * Returns an immutable set of the mappings in this map. The entries are in 310 * the same order as the parameters used to build this map. 311 */ entrySet()312 public abstract ImmutableSet<Entry<K, V>> entrySet(); 313 314 /** 315 * Returns an immutable set of the keys in this map. These keys are in 316 * the same order as the parameters used to build this map. 317 */ keySet()318 public abstract ImmutableSet<K> keySet(); 319 320 /** 321 * Returns an immutable collection of the values in this map. The values are 322 * in the same order as the parameters used to build this map. 323 */ values()324 public abstract ImmutableCollection<V> values(); 325 equals(@ullable Object object)326 @Override public boolean equals(@Nullable Object object) { 327 if (object == this) { 328 return true; 329 } 330 if (object instanceof Map) { 331 Map<?, ?> that = (Map<?, ?>) object; 332 return this.entrySet().equals(that.entrySet()); 333 } 334 return false; 335 } 336 hashCode()337 @Override public int hashCode() { 338 // not caching hash code since it could change if map values are mutable 339 // in a way that modifies their hash codes 340 return entrySet().hashCode(); 341 } 342 toString()343 @Override public String toString() { 344 StringBuilder result = new StringBuilder(size() * 16).append('{'); 345 Maps.standardJoiner.appendTo(result, this); 346 return result.append('}').toString(); 347 } 348 349 /** 350 * Serialized type for all ImmutableMap instances. It captures the logical 351 * contents and they are reconstructed using public factory methods. This 352 * ensures that the implementation types remain as implementation details. 353 */ 354 static class SerializedForm implements Serializable { 355 private final Object[] keys; 356 private final Object[] values; SerializedForm(ImmutableMap<?, ?> map)357 SerializedForm(ImmutableMap<?, ?> map) { 358 keys = new Object[map.size()]; 359 values = new Object[map.size()]; 360 int i = 0; 361 for (Entry<?, ?> entry : map.entrySet()) { 362 keys[i] = entry.getKey(); 363 values[i] = entry.getValue(); 364 i++; 365 } 366 } readResolve()367 Object readResolve() { 368 Builder<Object, Object> builder = new Builder<Object, Object>(); 369 return createMap(builder); 370 } createMap(Builder<Object, Object> builder)371 Object createMap(Builder<Object, Object> builder) { 372 for (int i = 0; i < keys.length; i++) { 373 builder.put(keys[i], values[i]); 374 } 375 return builder.build(); 376 } 377 private static final long serialVersionUID = 0; 378 } 379 writeReplace()380 Object writeReplace() { 381 return new SerializedForm(this); 382 } 383 } 384