1090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2008 The Guava Authors 3090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 4090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * you may not use this file except in compliance with the License. 6090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * You may obtain a copy of the License at 7090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 8090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 10090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * See the License for the specific language governing permissions and 14090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * limitations under the License. 15090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 16090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 17090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpackage com.google.common.collect; 18090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 19090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport static com.google.common.base.Preconditions.checkNotNull; 20090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport static com.google.common.collect.Iterables.getOnlyElement; 21090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtCompatible; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 24090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.io.Serializable; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.ArrayList; 26090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.Collections; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.HashMap; 28090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.List; 29090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.Map; 30090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 31090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport javax.annotation.Nullable; 32090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 33090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/** 34090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * An immutable, hash-based {@link Map} with reliable user-specified iteration 35090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * order. Does not permit null keys or values. 36090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 37090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * <p>Unlike {@link Collections#unmodifiableMap}, which is a <i>view</i> of a 38090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * separate map which can still change, an instance of {@code ImmutableMap} 39090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * contains its own data and will <i>never</i> change. {@code ImmutableMap} is 40090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * convenient for {@code public static final} maps ("constant maps") and also 41090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * lets you easily make a "defensive copy" of a map provided to your class by a 42090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * caller. 43090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p><i>Performance notes:</i> unlike {@link HashMap}, {@code ImmutableMap} is 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * not optimized for element types that have slow {@link Object#equals} or 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Object#hashCode} implementations. You can get better performance by 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * having your element type cache its own hash codes, and by making use of the 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * cached values to short-circuit a slow {@code equals} algorithm. 49090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 50090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Jesse Wilson 51090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Kevin Bourrillion 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 2.0 (imported from Google Collections Library) 53090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@GwtCompatible(serializable = true, emulated = true) 55090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson@SuppressWarnings("serial") // we're overriding default serialization 56090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpublic abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable { 57090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 58090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns the empty map. This map behaves and performs comparably to 59090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * {@link Collections#emptyMap}, and is preferable mainly for consistency 60090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * and maintainability of your code. 61090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 62090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Casting to any type is safe because the set will never hold any elements. 63090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") 64090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> of() { 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (ImmutableMap<K, V>) EmptyImmutableMap.INSTANCE; 66090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 67090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 68090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 69090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing a single entry. This map behaves and 70090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * performs comparably to {@link Collections#singletonMap} but will not accept 71090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * a null key or value. It is preferable mainly for consistency and 72090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * maintainability of your code. 73090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 74090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> of(K k1, V v1) { 75090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new SingletonImmutableMap<K, V>( 76090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson checkNotNull(k1), checkNotNull(v1)); 77090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 78090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 79090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 80090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing the given entries, in order. 81090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 82090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if duplicate keys are provided 83090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 84090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) { 85090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new RegularImmutableMap<K, V>(entryOf(k1, v1), entryOf(k2, v2)); 86090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 87090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 88090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 89090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing the given entries, in order. 90090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 91090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if duplicate keys are provided 92090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 93090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> of( 94090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson K k1, V v1, K k2, V v2, K k3, V v3) { 95090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new RegularImmutableMap<K, V>( 96090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); 97090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 98090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 99090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 100090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing the given entries, in order. 101090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 102090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if duplicate keys are provided 103090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 104090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> of( 105090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 106090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new RegularImmutableMap<K, V>( 107090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); 108090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 109090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 110090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 111090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing the given entries, in order. 112090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 113090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if duplicate keys are provided 114090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 115090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> of( 116090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 117090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new RegularImmutableMap<K, V>(entryOf(k1, v1), 118090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); 119090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 120090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 121090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // looking for of() with > 5 entries? Use the builder instead. 122090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 123090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 124090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns a new builder. The generated builder is equivalent to the builder 125090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * created by the {@link Builder} constructor. 126090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 127090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> Builder<K, V> builder() { 128090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new Builder<K, V>(); 129090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 130090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 131090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 132090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Verifies that {@code key} and {@code value} are non-null, and returns a new 133090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * immutable entry with those values. 134090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 135090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * <p>A call to {@link Map.Entry#setValue} on the returned entry will always 136090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * throw {@link UnsupportedOperationException}. 137090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 138090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static <K, V> Entry<K, V> entryOf(K key, V value) { 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return Maps.immutableEntry( 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkNotNull(key, "null key"), 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkNotNull(value, "null value")); 142090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 143090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 144090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 145090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * A builder for creating immutable map instances, especially {@code public 146090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * static final} maps ("constant maps"). Example: <pre> {@code 147090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 148090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * static final ImmutableMap<String, Integer> WORD_TO_INT = 149090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * new ImmutableMap.Builder<String, Integer>() 150090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .put("one", 1) 151090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .put("two", 2) 152090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .put("three", 3) 153090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .build();}</pre> 154090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 155090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are 156090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * even more convenient. 157090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 158090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * <p>Builder instances can be reused - it is safe to call {@link #build} 159090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * multiple times to build multiple maps in series. Each map is a superset of 160090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the maps created before it. 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 2.0 (imported from Google Collections Library) 163090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 164090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static class Builder<K, V> { 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final ArrayList<Entry<K, V>> entries = Lists.newArrayList(); 166090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 167090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 168090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Creates a new builder. The returned builder is equivalent to the builder 169090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * generated by {@link ImmutableMap#builder}. 170090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 171090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Builder() {} 172090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 173090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 174090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Associates {@code key} with {@code value} in the built map. Duplicate 175090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * keys are not allowed, and will cause {@link #build} to fail. 176090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 177090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Builder<K, V> put(K key, V value) { 178090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson entries.add(entryOf(key, value)); 179090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return this; 180090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 181090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 182090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Adds the given {@code entry} to the map, making it immutable if 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * necessary. Duplicate keys are not allowed, and will cause {@link #build} 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * to fail. 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert K key = entry.getKey(); 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert V value = entry.getValue(); 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (entry instanceof ImmutableEntry<?, ?>) { 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkNotNull(key); 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkNotNull(value); 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @SuppressWarnings("unchecked") // all supported methods are covariant 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Entry<K, V> immutableEntry = (Entry<K, V>) entry; 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert entries.add(immutableEntry); 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Directly calling entryOf(entry.getKey(), entry.getValue()) can cause 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // compilation error in Eclipse. 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert entries.add(entryOf(key, value)); 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 207090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Associates all of the given map's keys and values in the built map. 208090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Duplicate keys are not allowed, and will cause {@link #build} to fail. 209090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 210090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws NullPointerException if any key or value in {@code map} is null 211090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 212090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert entries.ensureCapacity(entries.size() + map.size()); 214090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (Entry<? extends K, ? extends V> entry : map.entrySet()) { 215090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson put(entry.getKey(), entry.getValue()); 216090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 217090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return this; 218090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 219090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * versions throw an IllegalStateException instead? 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 224090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 225090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 226090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns a newly-created immutable map. 227090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 228090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if duplicate keys were added 229090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 230090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public ImmutableMap<K, V> build() { 231090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return fromEntryList(entries); 232090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 233090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 234090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static <K, V> ImmutableMap<K, V> fromEntryList( 235090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson List<Entry<K, V>> entries) { 236090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson int size = entries.size(); 237090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson switch (size) { 238090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson case 0: 239090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return of(); 240090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson case 1: 241090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new SingletonImmutableMap<K, V>(getOnlyElement(entries)); 242090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson default: 243090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Entry<?, ?>[] entryArray 244090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson = entries.toArray(new Entry<?, ?>[entries.size()]); 245090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new RegularImmutableMap<K, V>(entryArray); 246090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 247090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 248090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 249090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 250090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 251090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing the same entries as {@code map}. If 252090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * {@code map} somehow contains entries with duplicate keys (for example, if 253090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * it is a {@code SortedMap} whose comparator is not <i>consistent with 254090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * equals</i>), the results of this method are undefined. 255090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Despite the method name, this method attempts to avoid actually copying 2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the data when it is safe to do so. The exact circumstances under which a 2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * copy will or will not be performed are undocumented and subject to change. 259090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 260090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws NullPointerException if any key or value in {@code map} is null 261090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 262090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K, V> ImmutableMap<K, V> copyOf( 263090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Map<? extends K, ? extends V> map) { 264090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if ((map instanceof ImmutableMap) && !(map instanceof ImmutableSortedMap)) { 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // TODO(user): Make ImmutableMap.copyOf(immutableBiMap) call copyOf() 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // on the ImmutableMap delegate(), rather than the bimap itself 2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 268090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") // safe since map is not writable 269090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map; 2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (!kvMap.isPartialView()) { 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return kvMap; 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 273090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 274090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 275090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") // we won't write to this array 276090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]); 277090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson switch (entries.length) { 278090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson case 0: 279090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return of(); 280090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson case 1: 281090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new SingletonImmutableMap<K, V>(entryOf( 282090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson entries[0].getKey(), entries[0].getValue())); 283090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson default: 284090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = 0; i < entries.length; i++) { 285090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson K k = entries[i].getKey(); 286090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson V v = entries[i].getValue(); 287090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson entries[i] = entryOf(k, v); 288090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 289090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new RegularImmutableMap<K, V>(entries); 290090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 291090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 292090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 293090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ImmutableMap() {} 294090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 295090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 296090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Guaranteed to throw an exception and leave the map unmodified. 297090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 298090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws UnsupportedOperationException always 299090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 301090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public final V put(K k, V v) { 302090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 303090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 304090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 305090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 306090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Guaranteed to throw an exception and leave the map unmodified. 307090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 308090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws UnsupportedOperationException always 309090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 311090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public final V remove(Object o) { 312090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 313090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 314090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 315090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 316090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Guaranteed to throw an exception and leave the map unmodified. 317090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 318090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws UnsupportedOperationException always 319090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 321090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public final void putAll(Map<? extends K, ? extends V> map) { 322090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 323090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 324090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 325090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 326090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Guaranteed to throw an exception and leave the map unmodified. 327090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 328090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws UnsupportedOperationException always 329090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 331090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public final void clear() { 332090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 333090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 334090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 336090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public boolean isEmpty() { 337090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return size() == 0; 338090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 339090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 341090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public boolean containsKey(@Nullable Object key) { 342090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return get(key) != null; 343090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 344090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 345090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Overriding to mark it Nullable 3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 347090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public abstract boolean containsValue(@Nullable Object value); 348090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 349090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Overriding to mark it Nullable 3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 351090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public abstract V get(@Nullable Object key); 352090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 353090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 354090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable set of the mappings in this map. The entries are in 355090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the same order as the parameters used to build this map. 356090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 358090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public abstract ImmutableSet<Entry<K, V>> entrySet(); 359090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 360090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 361090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable set of the keys in this map. These keys are in 362090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the same order as the parameters used to build this map. 363090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 365090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public abstract ImmutableSet<K> keySet(); 366090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 367090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 368090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable collection of the values in this map. The values are 369090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * in the same order as the parameters used to build this map. 370090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 372090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public abstract ImmutableCollection<V> values(); 373090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 374090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public boolean equals(@Nullable Object object) { 375090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (object == this) { 376090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return true; 377090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 378090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (object instanceof Map) { 379090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Map<?, ?> that = (Map<?, ?>) object; 380090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return this.entrySet().equals(that.entrySet()); 381090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 382090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return false; 383090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 384090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert abstract boolean isPartialView(); 3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 387090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public int hashCode() { 388090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // not caching hash code since it could change if map values are mutable 389090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // in a way that modifies their hash codes 390090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return entrySet().hashCode(); 391090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 392090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 393090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public String toString() { 3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return Maps.toStringImpl(this); 395090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 396090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 397090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 398090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Serialized type for all ImmutableMap instances. It captures the logical 399090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * contents and they are reconstructed using public factory methods. This 400090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * ensures that the implementation types remain as implementation details. 401090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 402090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static class SerializedForm implements Serializable { 403090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private final Object[] keys; 404090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private final Object[] values; 405090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson SerializedForm(ImmutableMap<?, ?> map) { 406090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson keys = new Object[map.size()]; 407090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson values = new Object[map.size()]; 408090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson int i = 0; 409090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (Entry<?, ?> entry : map.entrySet()) { 410090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson keys[i] = entry.getKey(); 411090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson values[i] = entry.getValue(); 412090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson i++; 413090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 414090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 415090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Object readResolve() { 416090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Builder<Object, Object> builder = new Builder<Object, Object>(); 417090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return createMap(builder); 418090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 419090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Object createMap(Builder<Object, Object> builder) { 420090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = 0; i < keys.length; i++) { 421090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson builder.put(keys[i], values[i]); 422090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 423090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return builder.build(); 424090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 425090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static final long serialVersionUID = 0; 426090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 427090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 428090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Object writeReplace() { 429090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new SerializedForm(this); 430090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 431090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson} 432