/* * 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.annotations.GwtCompatible; import com.google.common.base.Function; import com.google.common.base.Joiner.MapJoiner; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import java.io.Serializable; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; 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.TreeMap; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * Static utility methods pertaining to {@link Map} instances. Also see this * class's counterparts {@link Lists} and {@link Sets}. * * @author Kevin Bourrillion * @author Mike Bostock * @author Isaac Shum * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library) */ @GwtCompatible public final class Maps { private Maps() {} /** * Creates a <i>mutable</i>, empty {@code HashMap} instance. * * <p><b>Note:</b> if mutability is not required, use {@link * ImmutableMap#of()} instead. * * <p><b>Note:</b> if {@code K} is an {@code enum} type, use {@link * #newEnumMap} instead. * * @return a new, empty {@code HashMap} */ public static <K, V> HashMap<K, V> newHashMap() { return new HashMap<K, V>(); } /** * Creates a {@code HashMap} instance with enough capacity to hold the * specified number of elements without rehashing. * * @param expectedSize the expected size * @return a new, empty {@code HashMap} with enough * capacity to hold {@code expectedSize} elements without rehashing * @throws IllegalArgumentException if {@code expectedSize} is negative */ public static <K, V> HashMap<K, V> newHashMapWithExpectedSize( int expectedSize) { /* * The HashMap is constructed with an initialCapacity that's greater than * expectedSize. The larger value is necessary because HashMap resizes * its internal array if the map size exceeds loadFactor * initialCapacity. */ return new HashMap<K, V>(capacity(expectedSize)); } /** * Returns an appropriate value for the "capacity" (in reality, "minimum * table size") parameter of a {@link 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 <i>mutable</i> {@code HashMap} instance with the same mappings as * the specified map. * * <p><b>Note:</b> if mutability is not required, use {@link * ImmutableMap#copyOf(Map)} instead. * * <p><b>Note:</b> 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 new {@code HashMap} initialized with the mappings from * {@code map} */ public static <K, V> HashMap<K, V> newHashMap( Map<? extends K, ? extends V> map) { return new HashMap<K, V>(map); } /** * Creates a <i>mutable</i>, empty, insertion-ordered {@code LinkedHashMap} * instance. * * <p><b>Note:</b> if mutability is not required, use {@link * ImmutableMap#of()} instead. * * @return a new, empty {@code LinkedHashMap} */ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() { return new LinkedHashMap<K, V>(); } /** * Creates a <i>mutable</i>, insertion-ordered {@code LinkedHashMap} instance * with the same mappings as the specified map. * * <p><b>Note:</b> if mutability is not required, use {@link * ImmutableMap#copyOf(Map)} instead. * * @param map the mappings to be placed in the new map * @return a new, {@code LinkedHashMap} initialized with the * mappings from {@code map} */ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> map) { return new LinkedHashMap<K, V>(map); } /** * Creates a <i>mutable</i>, empty {@code TreeMap} instance using the natural * ordering of its elements. * * <p><b>Note:</b> if mutability is not required, use {@link * ImmutableSortedMap#of()} instead. * * @return a new, empty {@code TreeMap} */ @SuppressWarnings("unchecked") // eclipse doesn't like the raw Comparable public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() { return new TreeMap<K, V>(); } /** * Creates a <i>mutable</i> {@code TreeMap} instance with the same mappings as * the specified map and using the same ordering as the specified map. * * <p><b>Note:</b> if mutability is not required, use {@link * ImmutableSortedMap#copyOfSorted(SortedMap)} instead. * * @param map the sorted map whose mappings are to be placed in the new map * and whose comparator is to be used to sort the new map * @return a new {@code TreeMap} initialized with the mappings from {@code * map} and using the comparator of {@code map} */ public static <K, V> TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map) { return new TreeMap<K, V>(map); } /** * Creates a <i>mutable</i>, empty {@code TreeMap} instance using the given * comparator. * * <p><b>Note:</b> if mutability is not required, use {@code * ImmutableSortedMap.orderedBy(comparator).build()} instead. * * @param comparator the comparator to sort the keys with * @return a new, empty {@code TreeMap} */ public static <C, K extends C, V> TreeMap<K, V> newTreeMap( @Nullable Comparator<C> 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<Class<?>> comparator = null; // Map<Class<? extends Throwable>, String> map = newTreeMap(comparator); return new TreeMap<K, V>(comparator); } /** * Creates an {@code EnumMap} instance. * * @param type the key type for this map * @return a new, empty {@code EnumMap} */ public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Class<K> type) { return new EnumMap<K, V>(checkNotNull(type)); } /** * Creates an {@code EnumMap} with the same mappings as the specified map. * * @param map the map from which to initialize this {@code EnumMap} * @return a new {@code EnumMap} initialized with the mappings from {@code * map} * @throws IllegalArgumentException if {@code m} is not an {@code EnumMap} * instance and contains no mappings */ public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap( Map<K, ? extends V> map) { return new EnumMap<K, V>(map); } /** * Creates an {@code IdentityHashMap} instance. * * @return a new, empty {@code IdentityHashMap} */ public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() { return new IdentityHashMap<K, V>(); } /** * Returns a synchronized (thread-safe) bimap backed by the specified bimap. * In order to guarantee serial access, it is critical that <b>all</b> access * to the backing bimap is accomplished through the returned bimap. * * <p>It is imperative that the user manually synchronize on the returned map * when accessing any of its collection views: <pre> {@code * * BiMap<Long, String> map = Maps.synchronizedBiMap( * HashBiMap.<Long, String>create()); * ... * Set<Long> set = map.keySet(); // Needn't be in synchronized block * ... * synchronized (map) { // Synchronizing on map, not set! * Iterator<Long> it = set.iterator(); // Must be in synchronized block * while (it.hasNext()) { * foo(it.next()); * } * }}</pre> * * Failure to follow this advice may result in non-deterministic behavior. * * <p>The returned bimap will be serializable if the specified bimap is * serializable. * * @param bimap the bimap to be wrapped in a synchronized view * @return a sychronized view of the specified bimap */ public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) { return Synchronized.biMap(bimap, null); } /** * Computes the difference between two maps. This difference is an immutable * snapshot of the state of the maps at the time this method is called. It * will never change, even if the maps change at a later time. * * <p>Since this method uses {@code HashMap} instances internally, the keys of * the supplied maps must be well-behaved with respect to * {@link Object#equals} and {@link Object#hashCode}. * * <p><b>Note:</b>If you only need to know whether two maps have the same * mappings, call {@code left.equals(right)} instead of this method. * * @param left the map to treat as the "left" map for purposes of comparison * @param right the map to treat as the "right" map for purposes of comparison * @return the difference between the two maps */ public static <K, V> MapDifference<K, V> difference( Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) { Map<K, V> onlyOnLeft = newHashMap(); Map<K, V> onlyOnRight = new HashMap<K, V>(right); // will whittle it down Map<K, V> onBoth = newHashMap(); Map<K, MapDifference.ValueDifference<V>> differences = newHashMap(); boolean eq = true; for (Entry<? extends K, ? extends V> entry : left.entrySet()) { K leftKey = entry.getKey(); V leftValue = entry.getValue(); if (right.containsKey(leftKey)) { V rightValue = onlyOnRight.remove(leftKey); if (Objects.equal(leftValue, rightValue)) { onBoth.put(leftKey, leftValue); } else { eq = false; differences.put(leftKey, new ValueDifferenceImpl<V>( leftValue, rightValue)); } } else { eq = false; onlyOnLeft.put(leftKey, leftValue); } } boolean areEqual = eq && onlyOnRight.isEmpty(); return new MapDifferenceImpl<K, V>( areEqual, onlyOnLeft, onlyOnRight, onBoth, differences); } private static class MapDifferenceImpl<K, V> implements MapDifference<K, V> { final boolean areEqual; final Map<K, V> onlyOnLeft; final Map<K, V> onlyOnRight; final Map<K, V> onBoth; final Map<K, ValueDifference<V>> differences; MapDifferenceImpl(boolean areEqual, Map<K, V> onlyOnLeft, Map<K, V> onlyOnRight, Map<K, V> onBoth, Map<K, ValueDifference<V>> differences) { this.areEqual = areEqual; this.onlyOnLeft = Collections.unmodifiableMap(onlyOnLeft); this.onlyOnRight = Collections.unmodifiableMap(onlyOnRight); this.onBoth = Collections.unmodifiableMap(onBoth); this.differences = Collections.unmodifiableMap(differences); } public boolean areEqual() { return areEqual; } public Map<K, V> entriesOnlyOnLeft() { return onlyOnLeft; } public Map<K, V> entriesOnlyOnRight() { return onlyOnRight; } public Map<K, V> entriesInCommon() { return onBoth; } public Map<K, ValueDifference<V>> entriesDiffering() { return differences; } @Override public boolean equals(Object object) { if (object == this) { return true; } if (object instanceof MapDifference) { MapDifference<?, ?> other = (MapDifference<?, ?>) object; return entriesOnlyOnLeft().equals(other.entriesOnlyOnLeft()) && entriesOnlyOnRight().equals(other.entriesOnlyOnRight()) && entriesInCommon().equals(other.entriesInCommon()) && entriesDiffering().equals(other.entriesDiffering()); } return false; } @Override public int hashCode() { return Objects.hashCode(entriesOnlyOnLeft(), entriesOnlyOnRight(), entriesInCommon(), entriesDiffering()); } @Override public String toString() { if (areEqual) { return "equal"; } StringBuilder result = new StringBuilder("not equal"); if (!onlyOnLeft.isEmpty()) { result.append(": only on left=").append(onlyOnLeft); } if (!onlyOnRight.isEmpty()) { result.append(": only on right=").append(onlyOnRight); } if (!differences.isEmpty()) { result.append(": value differences=").append(differences); } return result.toString(); } } static class ValueDifferenceImpl<V> implements MapDifference.ValueDifference<V> { private final V left; private final V right; ValueDifferenceImpl(@Nullable V left, @Nullable V right) { this.left = left; this.right = right; } public V leftValue() { return left; } public V rightValue() { return right; } @Override public boolean equals(@Nullable Object object) { if (object instanceof MapDifference.ValueDifference<?>) { MapDifference.ValueDifference<?> that = (MapDifference.ValueDifference<?>) object; return Objects.equal(this.left, that.leftValue()) && Objects.equal(this.right, that.rightValue()); } return false; } @Override public int hashCode() { return Objects.hashCode(left, right); } @Override public String toString() { return "(" + left + ", " + right + ")"; } } /** * Returns an immutable map for which the {@link Map#values} are the given * elements in the given order, and each key is the product of invoking a * supplied function on its corresponding value. * * @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} is null, or * if {@code keyFunction} produces {@code null} for any value */ // TODO: consider returning a bimap, whose inverse view does lookups by // invoking the function. public static <K, V> ImmutableMap<K, V> uniqueIndex( Iterable<V> values, Function<? super V, K> keyFunction) { checkNotNull(keyFunction); ImmutableMap.Builder<K, V> builder = ImmutableMap.builder(); for (V value : values) { builder.put(keyFunction.apply(value), value); } return builder.build(); } /** * Creates an {@code ImmutableMap<String, String>} from a {@code Properties} * instance. Properties normally derive from {@code Map<Object, Object>}, but * they typically contain strings, which is awkward. This method lets you get * a plain-old-{@code Map} out of a {@code Properties}. * * @param properties a {@code Properties} object to be converted * @return an immutable map containing all the entries in * {@code properties} * @throws ClassCastException if any key in {@code Properties} is not a * {@code String} * @throws NullPointerException if any key or value in {@code Properties} is * null. */ public static ImmutableMap<String, String> fromProperties(Properties properties) { ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); for (Enumeration<?> e = properties.propertyNames(); e.hasMoreElements();) { String key = (String) e.nextElement(); builder.put(key, properties.getProperty(key)); } return builder.build(); } /** * Returns an immutable map entry with the specified key and value. The {@link * Entry#setValue} operation throws an {@link UnsupportedOperationException}. * * <p>The returned entry is serializable. * * @param key the key to be associated with the returned entry * @param value the value to be associated with the returned entry */ public static <K, V> Entry<K, V> immutableEntry( @Nullable final K key, @Nullable final V value) { return new ImmutableEntry<K, V>(key, value); } /** * Returns an unmodifiable view of the specified set of entries. The {@link * Entry#setValue} operation throws an {@link UnsupportedOperationException}, * as do any operations that would modify the returned set. * * @param entrySet the entries for which to return an unmodifiable view * @return an unmodifiable view of the entries */ static <K, V> Set<Entry<K, V>> unmodifiableEntrySet( final Set<Entry<K, V>> entrySet) { return new UnmodifiableEntrySet<K, V>(Collections.unmodifiableSet( entrySet)); } /** * Returns an unmodifiable view of the specified map entry. The {@link * Entry#setValue} operation throws an {@link UnsupportedOperationException}. * This also has the side-effect of redefining {@code equals} to comply with * the Entry contract, to avoid a possible nefarious implementation of * equals. * * @param entry the entry for which to return an unmodifiable view * @return an unmodifiable view of the entry */ private static <K, V> Entry<K, V> unmodifiableEntry(final Entry<K, V> entry) { checkNotNull(entry); return new AbstractMapEntry<K, V>() { @Override public K getKey() { return entry.getKey(); } @Override public V getValue() { return entry.getValue(); } }; } /** @see Multimaps#unmodifiableEntries */ static class UnmodifiableEntries<K, V> extends ForwardingCollection<Entry<K, V>> { private final Collection<Entry<K, V>> entries; UnmodifiableEntries(Collection<Entry<K, V>> entries) { this.entries = entries; } @Override protected Collection<Entry<K, V>> delegate() { return entries; } @Override public Iterator<Entry<K, V>> iterator() { final Iterator<Entry<K, V>> delegate = super.iterator(); return new ForwardingIterator<Entry<K, V>>() { @Override public Entry<K, V> next() { return unmodifiableEntry(super.next()); } @Override protected Iterator<Entry<K, V>> delegate() { return delegate; } }; } // See java.util.Collections.UnmodifiableEntrySet for details on attacks. @Override public Object[] toArray() { return ObjectArrays.toArrayImpl(this); } @Override public <T> T[] toArray(T[] array) { return ObjectArrays.toArrayImpl(this, array); } @Override public boolean contains(Object o) { return containsEntryImpl(delegate(), o); } @Override public boolean containsAll(Collection<?> c) { return Collections2.containsAll(this, c); } } /** @see Maps#unmodifiableEntrySet(Set) */ static class UnmodifiableEntrySet<K, V> extends UnmodifiableEntries<K, V> implements Set<Entry<K, V>> { UnmodifiableEntrySet(Set<Entry<K, V>> entries) { super(entries); } // See java.util.Collections.UnmodifiableEntrySet for details on attacks. @Override public boolean equals(@Nullable Object object) { return Collections2.setEquals(this, object); } @Override public int hashCode() { return Sets.hashCodeImpl(this); } } /** * Returns an unmodifiable view of the specified bimap. This method allows * modules to provide users with "read-only" access to internal bimaps. Query * operations on the returned bimap "read through" to the specified bimap, and * attemps to modify the returned map, whether direct or via its collection * views, result in an {@code UnsupportedOperationException}. * * <p>The returned bimap will be serializable if the specified bimap is * serializable. * * @param bimap the bimap for which an unmodifiable view is to be returned * @return an unmodifiable view of the specified bimap */ public static <K, V> BiMap<K, V> unmodifiableBiMap( BiMap<? extends K, ? extends V> bimap) { return new UnmodifiableBiMap<K, V>(bimap, null); } /** @see Maps#unmodifiableBiMap(BiMap) */ private static class UnmodifiableBiMap<K, V> extends ForwardingMap<K, V> implements BiMap<K, V>, Serializable { final Map<K, V> unmodifiableMap; final BiMap<? extends K, ? extends V> delegate; transient BiMap<V, K> inverse; transient Set<V> values; UnmodifiableBiMap(BiMap<? extends K, ? extends V> delegate, @Nullable BiMap<V, K> inverse) { unmodifiableMap = Collections.<K, V>unmodifiableMap(delegate); this.delegate = delegate; this.inverse = inverse; } @Override protected Map<K, V> delegate() { return unmodifiableMap; } public V forcePut(K key, V value) { throw new UnsupportedOperationException(); } public BiMap<V, K> inverse() { BiMap<V, K> result = inverse; return (result == null) ? inverse = new UnmodifiableBiMap<V, K>(delegate.inverse(), this) : result; } @Override public Set<V> values() { Set<V> result = values; return (result == null) ? values = Collections.<V>unmodifiableSet(delegate.values()) : result; } private static final long serialVersionUID = 0; } /** * Implements {@code Collection.contains} safely for forwarding collections of * map entries. If {@code o} is an instance of {@code Map.Entry}, it is * wrapped using {@link #unmodifiableEntry} to protect against a possible * nefarious equals method. * * <p>Note that {@code c} is the backing (delegate) collection, rather than * the forwarding collection. * * @param c the delegate (unwrapped) collection of map entries * @param o the object that might be contained in {@code c} * @return {@code true} if {@code c} contains {@code o} */ static <K, V> boolean containsEntryImpl(Collection<Entry<K, V>> c, Object o) { if (!(o instanceof Entry)) { return false; } return c.contains(unmodifiableEntry((Entry<?, ?>) o)); } /** * Implements {@code Collection.remove} safely for forwarding collections of * map entries. If {@code o} is an instance of {@code Map.Entry}, it is * wrapped using {@link #unmodifiableEntry} to protect against a possible * nefarious equals method. * * <p>Note that {@code c} is backing (delegate) collection, rather than the * forwarding collection. * * @param c the delegate (unwrapped) collection of map entries * @param o the object to remove from {@code c} * @return {@code true} if {@code c} was changed */ static <K, V> boolean removeEntryImpl(Collection<Entry<K, V>> c, Object o) { if (!(o instanceof Entry)) { return false; } return c.remove(unmodifiableEntry((Entry<?, ?>) o)); } /** * Returns a view of a map where each value is transformed by a function. All * other properties of the map, such as iteration order, are left intact. For * example, the code: * <pre> {@code * * Map<String, Integer> map = ImmutableMap.of("a", 4, "b", 9); * Function<Integer, Double> sqrt = new Function<Integer, Double>() { * public Double apply(Integer in) { * return Math.sqrt((int) in); * } * }; * Map<String, Double> transformed = Maps.transformValues(sqrt, map); * System.out.println(transformed);}</pre> * * ... prints {@code {a=2.0, b=3.0}}. * * <p>Changes in the underlying map are reflected in this view. Conversely, * this view supports removal operations, and these are reflected in the * underlying map. * * <p>It's acceptable for the underlying map to contain null keys, and even * null values provided that the function is capable of accepting null input. * The transformed map might contain null values, if the function sometimes * gives a null result. * * <p>The returned map is not thread-safe or serializable, even if the * underlying map is. * * <p>The function is applied lazily, invoked when needed. This is necessary * for the returned map to be a view, but it means that the function will be * applied many times for bulk operations like {@link Map#containsValue} and * {@code Map.toString()}. For this to perform well, {@code function} should * be fast. To avoid lazy evaluation when the returned map doesn't need to be * a view, copy the returned map into a new map of your choosing. */ public static <K, V1, V2> Map<K, V2> transformValues( Map<K, V1> fromMap, Function<? super V1, V2> function) { return new TransformedValuesMap<K, V1, V2>(fromMap, function); } private static class TransformedValuesMap<K, V1, V2> extends AbstractMap<K, V2> { final Map<K, V1> fromMap; final Function<? super V1, V2> function; TransformedValuesMap(Map<K, V1> fromMap, Function<? super V1, V2> function) { this.fromMap = checkNotNull(fromMap); this.function = checkNotNull(function); } @Override public int size() { return fromMap.size(); } @Override public boolean containsKey(Object key) { return fromMap.containsKey(key); } @Override public V2 get(Object key) { V1 value = fromMap.get(key); return (value != null || fromMap.containsKey(key)) ? function.apply(value) : null; } @Override public V2 remove(Object key) { return fromMap.containsKey(key) ? function.apply(fromMap.remove(key)) : null; } @Override public void clear() { fromMap.clear(); } EntrySet entrySet; @Override public Set<Entry<K, V2>> entrySet() { EntrySet result = entrySet; if (result == null) { entrySet = result = new EntrySet(); } return result; } class EntrySet extends AbstractSet<Entry<K, V2>> { @Override public int size() { return TransformedValuesMap.this.size(); } @Override public Iterator<Entry<K, V2>> iterator() { final Iterator<Entry<K, V1>> mapIterator = fromMap.entrySet().iterator(); return new Iterator<Entry<K, V2>>() { public boolean hasNext() { return mapIterator.hasNext(); } public Entry<K, V2> next() { final Entry<K, V1> entry = mapIterator.next(); return new AbstractMapEntry<K, V2>() { @Override public K getKey() { return entry.getKey(); } @Override public V2 getValue() { return function.apply(entry.getValue()); } }; } public void remove() { mapIterator.remove(); } }; } @Override public void clear() { fromMap.clear(); } @Override public boolean contains(Object o) { if (!(o instanceof Entry)) { return false; } Entry<?, ?> entry = (Entry<?, ?>) o; Object entryKey = entry.getKey(); Object entryValue = entry.getValue(); V2 mapValue = TransformedValuesMap.this.get(entryKey); if (mapValue != null) { return mapValue.equals(entryValue); } return entryValue == null && containsKey(entryKey); } @Override public boolean remove(Object o) { if (contains(o)) { Entry<?, ?> entry = (Entry<?, ?>) o; Object key = entry.getKey(); fromMap.remove(key); return true; } return false; } } } /** * Returns a map containing the mappings in {@code unfiltered} whose keys * satisfy a predicate. The returned map is a live view of {@code unfiltered}; * changes to one affect the other. * * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code * values()} views have iterators that don't support {@code remove()}, but all * other methods are supported by the map and its views. The map's {@code * put()} and {@code putAll()} methods throw an {@link * IllegalArgumentException} if a key that doesn't satisfy the predicate is * provided. * * <p>When methods such as {@code removeAll()} and {@code clear()} are called * on the filtered map or its views, only mappings whose keys satisfy the * filter will be removed from the underlying map. * * <p>The returned map isn't threadsafe or serializable, even if {@code * unfiltered} is. * * <p>Many of the filtered map's methods, such as {@code size()}, * iterate across every key/value mapping in the underlying map and determine * which satisfy the filter. When a live view is <i>not</i> needed, it may be * faster to copy the filtered map and use the copy. */ public static <K, V> Map<K, V> filterKeys( Map<K, V> unfiltered, final Predicate<? super K> keyPredicate) { checkNotNull(keyPredicate); Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() { public boolean apply(Entry<K, V> input) { return keyPredicate.apply(input.getKey()); } }; return (unfiltered instanceof AbstractFilteredMap) ? filterFiltered((AbstractFilteredMap<K, V>) unfiltered, entryPredicate) : new FilteredKeyMap<K, V>( checkNotNull(unfiltered), keyPredicate, entryPredicate); } /** * Returns a map containing the mappings in {@code unfiltered} whose values * satisfy a predicate. The returned map is a live view of {@code unfiltered}; * changes to one affect the other. * * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code * values()} views have iterators that don't support {@code remove()}, but all * other methods are supported by the map and its views. The {@link Map#put}, * {@link Map#putAll}, and {@link Entry#setValue} methods throw an {@link * IllegalArgumentException} if a value that doesn't satisfy the predicate is * provided. * * <p>When methods such as {@code removeAll()} and {@code clear()} are called * on the filtered map or its views, only mappings whose values satisfy the * filter will be removed from the underlying map. * * <p>The returned map isn't threadsafe or serializable, even if {@code * unfiltered} is. * * <p>Many of the filtered map's methods, such as {@code size()}, * iterate across every key/value mapping in the underlying map and determine * which satisfy the filter. When a live view is <i>not</i> needed, it may be * faster to copy the filtered map and use the copy. */ public static <K, V> Map<K, V> filterValues( Map<K, V> unfiltered, final Predicate<? super V> valuePredicate) { checkNotNull(valuePredicate); Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() { public boolean apply(Entry<K, V> input) { return valuePredicate.apply(input.getValue()); } }; return filterEntries(unfiltered, entryPredicate); } /** * Returns a map containing the mappings in {@code unfiltered} that satisfy a * predicate. The returned map is a live view of {@code unfiltered}; changes * to one affect the other. * * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code * values()} views have iterators that don't support {@code remove()}, but all * other methods are supported by the map and its views. The map's {@code * put()} and {@code putAll()} methods throw an {@link * IllegalArgumentException} if a key/value pair that doesn't satisfy the * predicate is provided. Similarly, the map's entries have a {@link * Entry#setValue} method that throws an {@link IllegalArgumentException} when * the existing key and the provided value don't satisfy the predicate. * * <p>When methods such as {@code removeAll()} and {@code clear()} are called * on the filtered map or its views, only mappings that satisfy the filter * will be removed from the underlying map. * * <p>The returned map isn't threadsafe or serializable, even if {@code * unfiltered} is. * * <p>Many of the filtered map's methods, such as {@code size()}, * iterate across every key/value mapping in the underlying map and determine * which satisfy the filter. When a live view is <i>not</i> needed, it may be * faster to copy the filtered map and use the copy. */ public static <K, V> Map<K, V> filterEntries( Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { checkNotNull(entryPredicate); return (unfiltered instanceof AbstractFilteredMap) ? filterFiltered((AbstractFilteredMap<K, V>) unfiltered, entryPredicate) : new FilteredEntryMap<K, V>(checkNotNull(unfiltered), entryPredicate); } /** * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when * filtering a filtered map. */ private static <K, V> Map<K, V> filterFiltered( AbstractFilteredMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) { Predicate<Entry<K, V>> predicate = Predicates.and(map.predicate, entryPredicate); return new FilteredEntryMap<K, V>(map.unfiltered, predicate); } private static abstract class AbstractFilteredMap<K, V> extends AbstractMap<K, V> { final Map<K, V> unfiltered; final Predicate<? super Entry<K, V>> predicate; AbstractFilteredMap(Map<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) { this.unfiltered = unfiltered; this.predicate = predicate; } boolean apply(Object key, V value) { // This method is called only when the key is in the map, implying that // key is a K. @SuppressWarnings("unchecked") K k = (K) key; return predicate.apply(Maps.immutableEntry(k, value)); } @Override public V put(K key, V value) { checkArgument(apply(key, value)); return unfiltered.put(key, value); } @Override public void putAll(Map<? extends K, ? extends V> map) { for (Entry<? extends K, ? extends V> entry : map.entrySet()) { checkArgument(apply(entry.getKey(), entry.getValue())); } unfiltered.putAll(map); } @Override public boolean containsKey(Object key) { return unfiltered.containsKey(key) && apply(key, unfiltered.get(key)); } @Override public V get(Object key) { V value = unfiltered.get(key); return ((value != null) && apply(key, value)) ? value : null; } @Override public boolean isEmpty() { return entrySet().isEmpty(); } @Override public V remove(Object key) { return containsKey(key) ? unfiltered.remove(key) : null; } Collection<V> values; @Override public Collection<V> values() { Collection<V> result = values; return (result == null) ? values = new Values() : result; } class Values extends AbstractCollection<V> { @Override public Iterator<V> iterator() { final Iterator<Entry<K, V>> entryIterator = entrySet().iterator(); return new UnmodifiableIterator<V>() { public boolean hasNext() { return entryIterator.hasNext(); } public V next() { return entryIterator.next().getValue(); } }; } @Override public int size() { return entrySet().size(); } @Override public void clear() { entrySet().clear(); } @Override public boolean isEmpty() { return entrySet().isEmpty(); } @Override public boolean remove(Object o) { Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator(); while (iterator.hasNext()) { Entry<K, V> entry = iterator.next(); if (Objects.equal(o, entry.getValue()) && predicate.apply(entry)) { iterator.remove(); return true; } } return false; } @Override public boolean removeAll(Collection<?> collection) { checkNotNull(collection); boolean changed = false; Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator(); while (iterator.hasNext()) { Entry<K, V> entry = iterator.next(); if (collection.contains(entry.getValue()) && predicate.apply(entry)) { iterator.remove(); changed = true; } } return changed; } @Override public boolean retainAll(Collection<?> collection) { checkNotNull(collection); boolean changed = false; Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator(); while (iterator.hasNext()) { Entry<K, V> entry = iterator.next(); if (!collection.contains(entry.getValue()) && predicate.apply(entry)) { iterator.remove(); changed = true; } } return changed; } @Override public Object[] toArray() { // creating an ArrayList so filtering happens once return Lists.newArrayList(iterator()).toArray(); } @Override public <T> T[] toArray(T[] array) { return Lists.newArrayList(iterator()).toArray(array); } } } private static class FilteredKeyMap<K, V> extends AbstractFilteredMap<K, V> { Predicate<? super K> keyPredicate; FilteredKeyMap(Map<K, V> unfiltered, Predicate<? super K> keyPredicate, Predicate<Entry<K, V>> entryPredicate) { super(unfiltered, entryPredicate); this.keyPredicate = keyPredicate; } Set<Entry<K, V>> entrySet; @Override public Set<Entry<K, V>> entrySet() { Set<Entry<K, V>> result = entrySet; return (result == null) ? entrySet = Sets.filter(unfiltered.entrySet(), predicate) : result; } Set<K> keySet; @Override public Set<K> keySet() { Set<K> result = keySet; return (result == null) ? keySet = Sets.filter(unfiltered.keySet(), keyPredicate) : result; } // The cast is called only when the key is in the unfiltered map, implying // that key is a K. @SuppressWarnings("unchecked") @Override public boolean containsKey(Object key) { return unfiltered.containsKey(key) && keyPredicate.apply((K) key); } } private static class FilteredEntryMap<K, V> extends AbstractFilteredMap<K, V> { /** * Entries in this set satisfy the predicate, but they don't validate the * input to {@code Entry.setValue()}. */ final Set<Entry<K, V>> filteredEntrySet; FilteredEntryMap(Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { super(unfiltered, entryPredicate); filteredEntrySet = Sets.filter(unfiltered.entrySet(), predicate); } Set<Entry<K, V>> entrySet; @Override public Set<Entry<K, V>> entrySet() { Set<Entry<K, V>> result = entrySet; return (result == null) ? entrySet = new EntrySet() : result; } private class EntrySet extends ForwardingSet<Entry<K, V>> { @Override protected Set<Entry<K, V>> delegate() { return filteredEntrySet; } @Override public Iterator<Entry<K, V>> iterator() { final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator(); return new UnmodifiableIterator<Entry<K, V>>() { public boolean hasNext() { return iterator.hasNext(); } public Entry<K, V> next() { final Entry<K, V> entry = iterator.next(); return new ForwardingMapEntry<K, V>() { @Override protected Entry<K, V> delegate() { return entry; } @Override public V setValue(V value) { checkArgument(apply(entry.getKey(), value)); return super.setValue(value); } }; } }; } } Set<K> keySet; @Override public Set<K> keySet() { Set<K> result = keySet; return (result == null) ? keySet = new KeySet() : result; } private class KeySet extends AbstractSet<K> { @Override public Iterator<K> iterator() { final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator(); return new UnmodifiableIterator<K>() { public boolean hasNext() { return iterator.hasNext(); } public K next() { return iterator.next().getKey(); } }; } @Override public int size() { return filteredEntrySet.size(); } @Override public void clear() { filteredEntrySet.clear(); } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object o) { if (containsKey(o)) { unfiltered.remove(o); return true; } return false; } @Override public boolean removeAll(Collection<?> collection) { checkNotNull(collection); // for GWT boolean changed = false; for (Object obj : collection) { changed |= remove(obj); } return changed; } @Override public boolean retainAll(Collection<?> collection) { checkNotNull(collection); // for GWT boolean changed = false; Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator(); while (iterator.hasNext()) { Entry<K, V> entry = iterator.next(); if (!collection.contains(entry.getKey()) && predicate.apply(entry)) { iterator.remove(); changed = true; } } return changed; } @Override public Object[] toArray() { // creating an ArrayList so filtering happens once return Lists.newArrayList(iterator()).toArray(); } @Override public <T> T[] toArray(T[] array) { return Lists.newArrayList(iterator()).toArray(array); } } } /** * {@code AbstractMap} extension that implements {@link #isEmpty()} as {@code * entrySet().isEmpty()} instead of {@code size() == 0} to speed up * implementations where {@code size()} is O(n), and it delegates the {@code * isEmpty()} methods of its key set and value collection to this * implementation. */ @GwtCompatible abstract static class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> { /** * Creates the entry set to be returned by {@link #entrySet()}. This method * is invoked at most once on a given map, at the time when {@code * entrySet} is first called. */ protected abstract Set<Entry<K, V>> createEntrySet(); private transient Set<Entry<K, V>> entrySet; @Override public Set<Entry<K, V>> entrySet() { Set<Entry<K, V>> result = entrySet; if (result == null) { entrySet = result = createEntrySet(); } return result; } private transient Set<K> keySet; @Override public Set<K> keySet() { Set<K> result = keySet; if (result == null) { final Set<K> delegate = super.keySet(); keySet = result = new ForwardingSet<K>() { @Override protected Set<K> delegate() { return delegate; } @Override public boolean isEmpty() { return ImprovedAbstractMap.this.isEmpty(); } }; } return result; } private transient Collection<V> values; @Override public Collection<V> values() { Collection<V> result = values; if (result == null) { final Collection<V> delegate = super.values(); values = result = new ForwardingCollection<V>() { @Override protected Collection<V> delegate() { return delegate; } @Override public boolean isEmpty() { return ImprovedAbstractMap.this.isEmpty(); } }; } return result; } /** * Returns {@code true} if this map contains no key-value mappings. * * <p>The implementation returns {@code entrySet().isEmpty()}. * * @return {@code true} if this map contains no key-value mappings */ @Override public boolean isEmpty() { return entrySet().isEmpty(); } } static final MapJoiner standardJoiner = Collections2.standardJoiner.withKeyValueSeparator("="); /** * Delegates to {@link Map#get}. Returns {@code null} on {@code * ClassCastException}. */ static <V> V safeGet(Map<?, V> map, Object key) { try { return map.get(key); } catch (ClassCastException e) { return null; } } /** * Delegates to {@link Map#containsKey}. Returns {@code false} on {@code * ClassCastException} */ static boolean safeContainsKey(Map<?, ?> map, Object key) { try { return map.containsKey(key); } catch (ClassCastException e) { return false; } } }