com.google.common.collect.Maps Maven / Gradle / Ivy
/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.base.Function;
import com.google.common.base.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.MapConstraints.ConstrainedMap;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
/**
* Provides static methods for creating mutable {@code Map} instances easily.
* You can replace code like:
*
* {@code Map map = new HashMap();}
*
* with just:
*
*
{@code Map map = Maps.newHashMap();}
*
* Supported today are: {@link HashMap}, {@link LinkedHashMap}, {@link
* ConcurrentHashMap}, {@link TreeMap}, and {@link EnumMap}.
*
*
See also this class's counterparts {@link Lists} and {@link Sets}.
*
*
WARNING: These factories do not support the full variety of tuning
* parameters available in the collection constructors. Use them only for
* collections which will always remain small, or for which the cost of future
* growth operations is not a concern.
*
* @author Kevin Bourrillion
* @author Mike Bostock
*/
public final class Maps {
private Maps() {}
/**
* Creates a {@code HashMap} instance.
*
*
Note: if {@code K} is an {@code enum} type, use {@link
* #newEnumMap} instead.
*
*
Note: if you don't actually need the resulting map to be mutable,
* use {@link Collections#emptyMap} instead.
*
* @return a newly-created, initially-empty {@code HashMap}
*/
public static HashMap newHashMap() {
return new HashMap();
}
/**
* Creates a {@code HashMap} instance with enough capacity to hold the
* specified number of elements without rehashing.
*
* @param expectedSize the expected size
* @return a newly-created {@code HashMap}, initially-empty, with enough
* capacity to hold {@code expectedSize} elements without rehashing.
* @throws IllegalArgumentException if {@code expectedSize} is negative
*/
public static HashMap newHashMapWithExpectedSize(
int expectedSize) {
return new HashMap(capacity(expectedSize));
}
/**
* Returns an appropriate value for the "capacity" (in reality, "minimum
* table size") parameter of a HashMap constructor, such that the resulting
* table will be between 25% and 50% full when it contains
* {@code expectedSize} entries.
*
* @throws IllegalArgumentException if {@code expectedSize} is negative
*/
static int capacity(int expectedSize) {
checkArgument(expectedSize >= 0);
return Math.max(expectedSize * 2, 16);
}
/**
* Creates a {@code HashMap} instance with the same mappings as the specified
* map.
*
* Note: if {@code K} is an {@link Enum} type, use {@link
* #newEnumMap} instead.
*
* @param map the mappings to be placed in the new map
* @return a newly-created {@code HashMap} initialized with the mappings from
* {@code map}
*/
public static HashMap newHashMap(Map map) {
return new HashMap(map);
}
/**
* Creates an insertion-ordered {@code LinkedHashMap} instance.
*
* @return a newly-created, initially-empty {@code LinkedHashMap}
*/
public static LinkedHashMap newLinkedHashMap() {
return new LinkedHashMap();
}
/**
* Creates an insertion-ordered {@code LinkedHashMap} instance with the same
* mappings as the specified map.
*
* @param map the mappings to be placed in the new map
* @return a newly-created, {@code LinkedHashMap} initialized with the
* mappings from {@code map}
*/
public static LinkedHashMap newLinkedHashMap(Map map) {
return new LinkedHashMap(map);
}
/**
* Creates a {@code ConcurrentHashMap} instance.
*
* @return a newly-created, initially-empty {@code ConcurrentHashMap}
*/
public static ConcurrentHashMap newConcurrentHashMap() {
return new ConcurrentHashMap();
}
/**
* Creates a {@code TreeMap} instance using the natural-order {@code
* Comparator}. Note: If {@code K} is an {@link Enum} type, and you
* don't require the map to implement {@link SortedMap} (only ordered
* iteration), use {@link #newEnumMap} instead.
*
* @return a newly-created, initially-empty {@code TreeMap}
*/
@SuppressWarnings("unchecked") // allow ungenerified Comparable types
public static TreeMap newTreeMap() {
return new TreeMap();
}
/**
* Creates a {@code TreeMap} instance using the given comparator.
*
* @param comparator the Comparator to sort the keys with
* @return a newly-created, initially-empty {@code TreeMap}
*/
public static TreeMap newTreeMap(
@Nullable Comparator comparator) {
// Ideally, the extra type parameter "C" shouldn't be necessary. It is a
// work-around of a compiler type inference quirk that prevents the
// following code from being compiled:
// Comparator> comparator = null;
// Map, String> map = newTreeMap(comparator);
return new TreeMap(comparator);
}
/**
* Creates an {@code EnumMap} instance.
*
* @param type the key type for this map
* @return a newly-created, initially-empty {@code EnumMap}
*/
public static , V> EnumMap newEnumMap(Class type) {
return new EnumMap(type);
}
/**
* Creates a {@code IdentityHashMap} instance.
*
* @return a newly-created, initially-empty {@code IdentityHashMap}
*/
public static IdentityHashMap newIdentityHashMap() {
return new IdentityHashMap();
}
/**
* Returns {@code true} if {@code map} contains an entry mapping {@code key}
* to {@code value}. If you are not concerned with null-safety you can simply
* use {@code map.get(key).equals(value)}.
*/
public static boolean containsEntry(
Map, ?> map, @Nullable Object key, @Nullable Object value) {
Object valueForKey = map.get(key);
return (valueForKey == null)
? value == null && map.containsKey(key)
: valueForKey.equals(value);
}
/**
* Creates a new immutable empty {@code Map} instance.
*
* @see Collections#emptyMap
*/
public static Map immutableMap() {
return Collections.emptyMap();
}
/**
* Creates a new immutable {@code Map} instance containing the given key-value
* pair.
*
* @see Collections#singletonMap
*/
public static Map immutableMap(
@Nullable K k1, @Nullable V v1) {
return Collections.singletonMap(k1, v1);
}
/**
* Creates a new immutable {@code Map} instance containing the given key-value
* pairs.
*
* @see ImmutableMapBuilder
*/
public static Map immutableMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2) {
return new ImmutableMapBuilder()
.put(k1, v1)
.put(k2, v2)
.getMap();
}
/**
* Creates a new immutable {@code Map} instance containing the given key-value
* pairs.
*
* @see ImmutableMapBuilder
*/
public static Map immutableMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2,
@Nullable K k3, @Nullable V v3) {
return new ImmutableMapBuilder()
.put(k1, v1)
.put(k2, v2)
.put(k3, v3)
.getMap();
}
/**
* Creates a new immutable {@code Map} instance containing the given key-value
* pairs.
*
* @see ImmutableMapBuilder
*/
public static Map immutableMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2,
@Nullable K k3, @Nullable V v3,
@Nullable K k4, @Nullable V v4) {
return new ImmutableMapBuilder()
.put(k1, v1)
.put(k2, v2)
.put(k3, v3)
.put(k4, v4)
.getMap();
}
/**
* Creates a new immutable {@code Map} instance containing the given key-value
* pairs.
*
* @see ImmutableMapBuilder
*/
public static Map immutableMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2,
@Nullable K k3, @Nullable V v3,
@Nullable K k4, @Nullable V v4,
@Nullable K k5, @Nullable V v5) {
return new ImmutableMapBuilder()
.put(k1, v1)
.put(k2, v2)
.put(k3, v3)
.put(k4, v4)
.put(k5, v5)
.getMap();
}
/*
* Please use ImmutableMapBuilder directly if you are looking for overloads
* for 6 or more key-value pairs.
*/
/**
* Creates a new immutable empty {@code BiMap} instance.
*/
public static BiMap immutableBiMap() {
return new ImmutableBiMapBuilder().getBiMap();
}
/**
* Creates a new immutable {@code BiMap} instance containing the given
* key-value pair.
*/
public static BiMap immutableBiMap(
@Nullable K k1, @Nullable V v1) {
return new ImmutableBiMapBuilder()
.put(k1, v1)
.getBiMap();
}
/**
* Creates a new immutable {@code BiMap} instance containing the given
* key-value pairs.
*
* @see ImmutableBiMapBuilder
*/
public static BiMap immutableBiMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2) {
return new ImmutableBiMapBuilder()
.put(k1, v1)
.put(k2, v2)
.getBiMap();
}
/**
* Creates a new immutable {@code BiMap} instance containing the given
* key-value pairs.
*
* @see ImmutableBiMapBuilder
*/
public static BiMap immutableBiMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2,
@Nullable K k3, @Nullable V v3) {
return new ImmutableBiMapBuilder()
.put(k1, v1)
.put(k2, v2)
.put(k3, v3)
.getBiMap();
}
/**
* Creates a new immutable {@code BiMap} instance containing the given
* key-value pairs.
*
* @see ImmutableBiMapBuilder
*/
public static BiMap immutableBiMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2,
@Nullable K k3, @Nullable V v3,
@Nullable K k4, @Nullable V v4) {
return new ImmutableBiMapBuilder()
.put(k1, v1)
.put(k2, v2)
.put(k3, v3)
.put(k4, v4)
.getBiMap();
}
/**
* Creates a new immutable {@code BiMap} instance containing the given
* key-value pairs.
*
* @see ImmutableBiMapBuilder
*/
public static BiMap immutableBiMap(
@Nullable K k1, @Nullable V v1,
@Nullable K k2, @Nullable V v2,
@Nullable K k3, @Nullable V v3,
@Nullable K k4, @Nullable V v4,
@Nullable K k5, @Nullable V v5) {
return new ImmutableBiMapBuilder()
.put(k1, v1)
.put(k2, v2)
.put(k3, v3)
.put(k4, v4)
.put(k5, v5)
.getBiMap();
}
/*
* Please use ImmutableBiMapBuilder directly if you are looking for overloads
* for 6 or more key-value pairs.
*/
/**
* Returns a synchronized (thread-safe) bimap backed by the specified bimap.
* In order to guarantee serial access, it is critical that all access
* to the backing bimap is accomplished through the returned bimap.
*
* It is imperative that the user manually synchronize on the returned map
* when accessing any of its collection views:
*
*
Bimap<K,V> m = Maps.synchronizedBiMap(
* new HashBiMap<K,V>());
* ...
* Set<K> s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (m) { // Synchronizing on m, not s!
* Iterator<K> i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param bimap the bimap to be wrapped in a synchronized view
* @return a sychronized view of the specified bimap
*/
public static BiMap synchronizedBiMap(BiMap bimap) {
return Synchronized.biMap(bimap, null);
}
/**
* Returns a sorted set view of the keys contained in the specified map. The
* set is backed by the map, so changes to the map are reflected in the set,
* and vice versa. If the map is modified while an iteration over the set is
* in progress (except through the iterator's own {@code remove} operation),
* the results of the iteration are undefined. The set supports element
* removal, which removes the corresponding mapping from the map, via the
* {@code Iterator.remove}, {@code Set.remove}, {@code removeAll}, {@code
* removeAll}, and {@code clear} operations. It does not support the add or
* {@code addAll} operations.
*
* @return a sorted set view of the keys contained in the specified map.
*/
public static SortedSet sortedKeySet(SortedMap map) {
return new SortedMapKeySet(map);
}
private static class SortedMapKeySet extends ForwardingSet
implements SortedSet {
final SortedMap map;
SortedMapKeySet(SortedMap map) {
super(map.keySet());
this.map = map;
}
public Comparator super K> comparator() {
return map.comparator();
}
public K first() {
return map.firstKey();
}
public SortedSet headSet(K toElement) {
return new SortedMapKeySet(map.headMap(toElement));
}
public K last() {
return map.lastKey();
}
public SortedSet subSet(K fromElement, K toElement) {
return new SortedMapKeySet(map.subMap(fromElement, toElement));
}
public SortedSet tailSet(K fromElement) {
return new SortedMapKeySet(map.tailMap(fromElement));
}
}
/**
* Creates an index {@code Map} that contains the results of applying a
* specified function to each item in an {@code Iterable} of values. Each
* value will be stored as a value in the resulting map. The key used to store
* that value in the map will be the result of calling the function on that
* value. Neither keys nor values are allowed to be null. It is an error if
* the function produces the same key for more than one value in the input
* collection.
*
* @param values the values to use when constructing the {@code Map}
* @param keyFunction the function used to produce the key for each value
* @return a map mapping the result of evaluating the function {@code
* keyFunction} on each value in the input collection to that value
* @throws IllegalArgumentException if {@code keyFunction} produces the same
* key for more than one value in the input collection
* @throws NullPointerException if any elements of {@code values} are null, or
* if {@code keyFunction} produces {@code null} for any value
*/
public static Map uniqueIndex(Iterable extends V> values,
Function super V, ? extends K> keyFunction) {
HashMap newMap;
if (values instanceof Collection>) {
// If it's really a collection, take advantage of knowing the size
@SuppressWarnings("unchecked")
Collection extends V> collection = (Collection extends V>) values;
newMap = new HashMap(collection.size());
} else {
newMap = new HashMap();
}
return uniqueIndex(newMap, values.iterator(), keyFunction);
}
/**
* Creates an index {@code Map} that contains the results of applying a
* specified function to each item in a {@code Collection} of values. Each
* value will be stored as a value in the resulting map. The key used to store
* that value in the map will be the result of calling the function on that
* value. Neither keys nor values are allowed to be null. It is an error if
* the function produces the same key for more than one value in the input
* collection.
*
* @param values the values to use when constructing the {@code Map}
* @param keyFunction the function used to produce the key for each value
* @return {@code Map} mapping the result of evaluating the function {@code
* keyFunction} on each value in the input collection to that value
* @throws IllegalArgumentException if {@code keyFunction} produces the same
* key for more than one value in the input collection
* @throws NullPointerException if any elements of {@code values} are null, or
* if {@code keyFunction} produces {@code null} for any value
*/
public static Map uniqueIndex(Collection extends V> values,
Function super V, ? extends K> keyFunction) {
return uniqueIndex(new HashMap(values.size() * 2),
values.iterator(), keyFunction);
}
/**
* Creates an index {@code Map} that contains the results of applying a
* specified function to each item in an {@code Iterator} of values. Each
* value will be stored as a value in the resulting map. The key used to store
* that value in the map will be the result of calling the function on that
* value. Neither keys nor values are allowed to be null. It is an error if
* the function produces the same key for more than one value in the input
* collection.
*
* @param values the values to use when constructing the {@code Map}
* @param keyFunction the function used to produce the key for each value
* @return {@code Map} mapping the result of evaluating the function {@code
* keyFunction} on each value in the input collection to that value
* @throws IllegalArgumentException if {@code keyFunction} produces the same
* key for more than one value in the input collection
* @throws NullPointerException if any elements of {@code values} are null, or
* if {@code keyFunction} produces {@code null} for any value
*/
public static Map uniqueIndex(Iterator extends V> values,
Function super V, ? extends K> keyFunction) {
return uniqueIndex(new HashMap(), values, keyFunction);
}
private static Map uniqueIndex(
Map map, Iterator extends V> values,
Function super V, ? extends K> keyFunction) {
checkNotNull(keyFunction);
while (values.hasNext()) {
V value = checkNotNull(values.next(), "null index values not allowed");
K key = checkNotNull(keyFunction.apply(value),
"null index keys not allowed");
checkArgument(map.put(key, value) == null, "Duplicate key: %s", key);
}
return map;
}
/**
* Creates a {@code Map} from a {@code Properties} instance.
* Properties normally derive from {@code Map