diff options
Diffstat (limited to 'guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java')
-rw-r--r-- | guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java | 919 |
1 files changed, 191 insertions, 728 deletions
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java index fd6909d..78165de 100644 --- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java +++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java @@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Equivalence; +import com.google.common.base.Equivalences; import com.google.common.base.Function; import com.google.common.base.Joiner.MapJoiner; import com.google.common.base.Objects; @@ -34,6 +35,7 @@ import com.google.common.primitives.Ints; 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; @@ -46,20 +48,14 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; -import java.util.SortedSet; import java.util.TreeMap; import java.util.concurrent.ConcurrentMap; import javax.annotation.Nullable; /** - * Static utility methods pertaining to {@link Map} instances (including instances of - * {@link SortedMap}, {@link BiMap}, etc.). Also see this class's counterparts - * {@link Lists}, {@link Sets} and {@link Queues}. - * - * <p>See the Guava User Guide article on <a href= - * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Maps"> - * {@code Maps}</a>. + * 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 @@ -71,60 +67,6 @@ import javax.annotation.Nullable; public final class Maps { private Maps() {} - private enum EntryFunction implements Function<Entry, Object> { - KEY { - @Override - @Nullable - public Object apply(Entry entry) { - return entry.getKey(); - } - }, - VALUE { - @Override - @Nullable - public Object apply(Entry entry) { - return entry.getValue(); - } - }; - } - - @SuppressWarnings("unchecked") - static <K> Function<Entry<K, ?>, K> keyFunction() { - return (Function) EntryFunction.KEY; - } - - static <V> Function<Entry<?, V>, V> valueFunction() { - return (Function) EntryFunction.VALUE; - } - - /** - * Returns an immutable map instance containing the given entries. - * Internally, the returned set will be backed by an {@link EnumMap}. - * - * <p>The iteration order of the returned map follows the enum's iteration - * order, not the order in which the elements appear in the given map. - * - * @param map the map to make an immutable copy of - * @return an immutable map containing those entries - * @since 14.0 - */ - @GwtCompatible(serializable = true) - @Beta - public static <K extends Enum<K>, V> ImmutableMap<K, V> immutableEnumMap( - Map<K, V> map) { - if (map instanceof ImmutableEnumMap) { - return (ImmutableEnumMap<K, V>) map; - } else if (map.isEmpty()) { - return ImmutableMap.of(); - } else { - for (Map.Entry<K, V> entry : map.entrySet()) { - checkNotNull(entry.getKey()); - checkNotNull(entry.getValue()); - } - return ImmutableEnumMap.asImmutable(new EnumMap<K, V>(map)); - } - } - /** * Creates a <i>mutable</i>, empty {@code HashMap} instance. * @@ -324,6 +266,38 @@ public final class Maps { } /** + * 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. @@ -347,7 +321,7 @@ public final class Maps { SortedMapDifference<K, V> result = difference(sortedLeft, right); return result; } - return difference(left, right, Equivalence.equals()); + return difference(left, right, Equivalences.equals()); } /** @@ -519,7 +493,7 @@ public final class Maps { } @Override public boolean equals(@Nullable Object object) { - if (object instanceof MapDifference.ValueDifference) { + if (object instanceof MapDifference.ValueDifference<?>) { MapDifference.ValueDifference<?> that = (MapDifference.ValueDifference<?>) object; return Objects.equal(this.left, that.leftValue()) @@ -556,6 +530,7 @@ public final class Maps { * @return the difference between the two maps * @since 11.0 */ + @Beta public static <K, V> SortedMapDifference<K, V> difference( SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) { checkNotNull(left); @@ -640,313 +615,6 @@ public final class Maps { } return (Comparator<E>) Ordering.natural(); } - - /** - * Returns a view of the set as a map, mapping keys from the set according to - * the specified function. - * - * <p>Specifically, for each {@code k} in the backing set, the returned map - * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code - * keySet}, {@code values}, and {@code entrySet} views of the returned map - * iterate in the same order as the backing set. - * - * <p>Modifications to the backing set are read through to the returned map. - * The returned map supports removal operations if the backing set does. - * Removal operations write through to the backing set. The returned map - * does not support put operations. - * - * <p><b>Warning</b>: If the function rejects {@code null}, caution is - * required to make sure the set does not contain {@code null}, because the - * view cannot stop {@code null} from being added to the set. - * - * <p><b>Warning:</b> This method assumes that for any instance {@code k} of - * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also - * of type {@code K}. Using a key type for which this may not hold, such as - * {@code ArrayList}, may risk a {@code ClassCastException} when calling - * methods on the resulting map view. - * - * @since 14.0 - */ - @Beta - public static <K, V> Map<K, V> asMap( - Set<K> set, Function<? super K, V> function) { - if (set instanceof SortedSet) { - return asMap((SortedSet<K>) set, function); - } else { - return new AsMapView<K, V>(set, function); - } - } - - /** - * Returns a view of the sorted set as a map, mapping keys from the set - * according to the specified function. - * - * <p>Specifically, for each {@code k} in the backing set, the returned map - * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code - * keySet}, {@code values}, and {@code entrySet} views of the returned map - * iterate in the same order as the backing set. - * - * <p>Modifications to the backing set are read through to the returned map. - * The returned map supports removal operations if the backing set does. - * Removal operations write through to the backing set. The returned map does - * not support put operations. - * - * <p><b>Warning</b>: If the function rejects {@code null}, caution is - * required to make sure the set does not contain {@code null}, because the - * view cannot stop {@code null} from being added to the set. - * - * <p><b>Warning:</b> This method assumes that for any instance {@code k} of - * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also of - * type {@code K}. Using a key type for which this may not hold, such as - * {@code ArrayList}, may risk a {@code ClassCastException} when calling - * methods on the resulting map view. - * - * @since 14.0 - */ - @Beta - public static <K, V> SortedMap<K, V> asMap( - SortedSet<K> set, Function<? super K, V> function) { - return Platform.mapsAsMapSortedSet(set, function); - } - - static <K, V> SortedMap<K, V> asMapSortedIgnoreNavigable(SortedSet<K> set, - Function<? super K, V> function) { - return new SortedAsMapView<K, V>(set, function); - } - - private static class AsMapView<K, V> extends ImprovedAbstractMap<K, V> { - - private final Set<K> set; - final Function<? super K, V> function; - - Set<K> backingSet() { - return set; - } - - AsMapView(Set<K> set, Function<? super K, V> function) { - this.set = checkNotNull(set); - this.function = checkNotNull(function); - } - - @Override - public Set<K> keySet() { - // probably not worth caching - return removeOnlySet(backingSet()); - } - - @Override - public Collection<V> values() { - // probably not worth caching - return Collections2.transform(set, function); - } - - @Override - public int size() { - return backingSet().size(); - } - - @Override - public boolean containsKey(@Nullable Object key) { - return backingSet().contains(key); - } - - @Override - public V get(@Nullable Object key) { - if (backingSet().contains(key)) { - @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it - K k = (K) key; - return function.apply(k); - } else { - return null; - } - } - - @Override - public V remove(@Nullable Object key) { - if (backingSet().remove(key)) { - @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it - K k = (K) key; - return function.apply(k); - } else { - return null; - } - } - - @Override - public void clear() { - backingSet().clear(); - } - - @Override - protected Set<Entry<K, V>> createEntrySet() { - return new EntrySet<K, V>() { - @Override - Map<K, V> map() { - return AsMapView.this; - } - - @Override - public Iterator<Entry<K, V>> iterator() { - return asSetEntryIterator(backingSet(), function); - } - }; - } - } - - private static <K, V> Iterator<Entry<K, V>> asSetEntryIterator( - Set<K> set, final Function<? super K, V> function) { - return new TransformedIterator<K, Entry<K,V>>(set.iterator()) { - @Override - Entry<K, V> transform(K key) { - return Maps.immutableEntry(key, function.apply(key)); - } - }; - } - - private static class SortedAsMapView<K, V> extends AsMapView<K, V> - implements SortedMap<K, V> { - - SortedAsMapView(SortedSet<K> set, Function<? super K, V> function) { - super(set, function); - } - - @Override - SortedSet<K> backingSet() { - return (SortedSet<K>) super.backingSet(); - } - - @Override - public Comparator<? super K> comparator() { - return backingSet().comparator(); - } - - @Override - public Set<K> keySet() { - return removeOnlySortedSet(backingSet()); - } - - @Override - public SortedMap<K, V> subMap(K fromKey, K toKey) { - return asMap(backingSet().subSet(fromKey, toKey), function); - } - - @Override - public SortedMap<K, V> headMap(K toKey) { - return asMap(backingSet().headSet(toKey), function); - } - - @Override - public SortedMap<K, V> tailMap(K fromKey) { - return asMap(backingSet().tailSet(fromKey), function); - } - - @Override - public K firstKey() { - return backingSet().first(); - } - - @Override - public K lastKey() { - return backingSet().last(); - } - } - - private static <E> Set<E> removeOnlySet(final Set<E> set) { - return new ForwardingSet<E>() { - @Override - protected Set<E> delegate() { - return set; - } - - @Override - public boolean add(E element) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection<? extends E> es) { - throw new UnsupportedOperationException(); - } - }; - } - - private static <E> SortedSet<E> removeOnlySortedSet(final SortedSet<E> set) { - return new ForwardingSortedSet<E>() { - @Override - protected SortedSet<E> delegate() { - return set; - } - - @Override - public boolean add(E element) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection<? extends E> es) { - throw new UnsupportedOperationException(); - } - - @Override - public SortedSet<E> headSet(E toElement) { - return removeOnlySortedSet(super.headSet(toElement)); - } - - @Override - public SortedSet<E> subSet(E fromElement, E toElement) { - return removeOnlySortedSet(super.subSet(fromElement, toElement)); - } - - @Override - public SortedSet<E> tailSet(E fromElement) { - return removeOnlySortedSet(super.tailSet(fromElement)); - } - }; - } - - /** - * Returns an immutable map for which the given {@code keys} are mapped to - * values by the given function in the order they appear in the original - * iterable. If {@code keys} contains duplicate elements, the returned map - * will contain each distinct key once in the order it first appears in - * {@code keys}. - * - * @throws NullPointerException if any element of {@code keys} is - * {@code null}, or if {@code valueFunction} produces {@code null} - * for any key - * @since 14.0 - */ - @Beta - public static <K, V> ImmutableMap<K, V> toMap(Iterable<K> keys, - Function<? super K, V> valueFunction) { - return toMap(keys.iterator(), valueFunction); - } - - /** - * Returns an immutable map for which the given {@code keys} are mapped to - * values by the given function in the order they appear in the original - * iterator. If {@code keys} contains duplicate elements, the returned map - * will contain each distinct key once in the order it first appears in - * {@code keys}. - * - * @throws NullPointerException if any element of {@code keys} is - * {@code null}, or if {@code valueFunction} produces {@code null} - * for any key - * @since 14.0 - */ - @Beta - public static <K, V> ImmutableMap<K, V> toMap(Iterator<K> keys, - Function<? super K, V> valueFunction) { - checkNotNull(valueFunction); - // Using LHM instead of a builder so as not to fail on duplicate keys - Map<K, V> builder = newLinkedHashMap(); - while (keys.hasNext()) { - K key = keys.next(); - builder.put(key, valueFunction.apply(key)); - } - return ImmutableMap.copyOf(builder); - } - /** * 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 @@ -967,6 +635,24 @@ public final class Maps { } /** + * <b>Deprecated.</b> + * + * @since 10.0 + * @deprecated use {@link #uniqueIndex(Iterator, Function)} by casting {@code + * values} to {@code Iterator<V>}, or better yet, by implementing only + * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled + * for deletion in March 2012.</b> + */ + @Beta + @Deprecated + public static <K, V, I extends Object & Iterable<V> & Iterator<V>> + ImmutableMap<K, V> uniqueIndex( + I values, Function<? super V, K> keyFunction) { + Iterable<V> valuesIterable = checkNotNull(values); + return uniqueIndex(valuesIterable, keyFunction); + } + + /** * 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. @@ -1128,38 +814,6 @@ public final class Maps { } /** - * 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); - } - - /** * 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 @@ -1182,7 +836,7 @@ public final class Maps { extends ForwardingMap<K, V> implements BiMap<K, V>, Serializable { final Map<K, V> unmodifiableMap; final BiMap<? extends K, ? extends V> delegate; - BiMap<V, K> inverse; + transient BiMap<V, K> inverse; transient Set<V> values; UnmodifiableBiMap(BiMap<? extends K, ? extends V> delegate, @@ -1256,8 +910,16 @@ public final class Maps { * 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 transformEntries(fromMap, asEntryTransformer(function)); + Map<K, V1> fromMap, final Function<? super V1, V2> function) { + checkNotNull(function); + EntryTransformer<K, V1, V2> transformer = + new EntryTransformer<K, V1, V2>() { + @Override + public V2 transformEntry(K key, V1 value) { + return function.apply(value); + } + }; + return transformEntries(fromMap, transformer); } /** @@ -1299,20 +961,18 @@ public final class Maps { * * @since 11.0 */ + @Beta public static <K, V1, V2> SortedMap<K, V2> transformValues( - SortedMap<K, V1> fromMap, Function<? super V1, V2> function) { - return transformEntries(fromMap, asEntryTransformer(function)); - } - - private static <K, V1, V2> EntryTransformer<K, V1, V2> - asEntryTransformer(final Function<? super V1, V2> function) { + SortedMap<K, V1> fromMap, final Function<? super V1, V2> function) { checkNotNull(function); - return new EntryTransformer<K, V1, V2>() { - @Override - public V2 transformEntry(K key, V1 value) { - return function.apply(value); - } - }; + EntryTransformer<K, V1, V2> transformer = + new EntryTransformer<K, V1, V2>() { + @Override + public V2 transformEntry(K key, V1 value) { + return function.apply(value); + } + }; + return transformEntries(fromMap, transformer); } /** @@ -1427,14 +1087,9 @@ public final class Maps { * * @since 11.0 */ + @Beta public static <K, V1, V2> SortedMap<K, V2> transformEntries( - SortedMap<K, V1> fromMap, - EntryTransformer<? super K, ? super V1, V2> transformer) { - return Platform.mapsTransformEntriesSortedMap(fromMap, transformer); - } - - static <K, V1, V2> SortedMap<K, V2> transformEntriesIgnoreNavigable( - SortedMap<K, V1> fromMap, + final SortedMap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer) { return new TransformedEntriesSortedMap<K, V1, V2>(fromMap, transformer); } @@ -1526,23 +1181,17 @@ public final class Maps { } @Override public Iterator<Entry<K, V2>> iterator() { - return new TransformedIterator<Entry<K, V1>, Entry<K, V2>>( - fromMap.entrySet().iterator()) { - @Override - Entry<K, V2> transform(final Entry<K, V1> entry) { - return new AbstractMapEntry<K, V2>() { - @Override - public K getKey() { - return entry.getKey(); + final Iterator<Entry<K, V1>> backingIterator = + fromMap.entrySet().iterator(); + return Iterators.transform(backingIterator, + new Function<Entry<K, V1>, Entry<K, V2>>() { + @Override public Entry<K, V2> apply(Entry<K, V1> entry) { + return immutableEntry( + entry.getKey(), + transformer.transformEntry(entry.getKey(), + entry.getValue())); } - - @Override - public V2 getValue() { - return transformer.transformEntry(entry.getKey(), entry.getValue()); - } - }; - } - }; + }); } }; } @@ -1600,32 +1249,7 @@ public final class Maps { @Override public SortedMap<K, V2> tailMap(K fromKey) { return transformEntries(fromMap().tailMap(fromKey), transformer); } - } - - private static final class KeyPredicate<K, V> implements Predicate<Entry<K, V>> { - private final Predicate<? super K> keyPredicate; - - KeyPredicate(Predicate<? super K> keyPredicate) { - this.keyPredicate = checkNotNull(keyPredicate); - } - @Override - public boolean apply(Entry<K, V> input) { - return keyPredicate.apply(input.getKey()); - } - } - - private static final class ValuePredicate<K, V> implements Predicate<Entry<K, V>> { - private final Predicate<? super V> valuePredicate; - - ValuePredicate(Predicate<? super V> valuePredicate) { - this.valuePredicate = checkNotNull(valuePredicate); - } - - @Override - public boolean apply(Entry<K, V> input) { - return valuePredicate.apply(input.getValue()); - } } /** @@ -1660,11 +1284,15 @@ public final class Maps { Map<K, V> unfiltered, final Predicate<? super K> keyPredicate) { if (unfiltered instanceof SortedMap) { return filterKeys((SortedMap<K, V>) unfiltered, keyPredicate); - } else if (unfiltered instanceof BiMap) { - return filterKeys((BiMap<K, V>) unfiltered, keyPredicate); } checkNotNull(keyPredicate); - Predicate<Entry<K, V>> entryPredicate = new KeyPredicate<K, V>(keyPredicate); + Predicate<Entry<K, V>> entryPredicate = + new Predicate<Entry<K, V>>() { + @Override + 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>( @@ -1701,42 +1329,19 @@ public final class Maps { * * @since 11.0 */ + @Beta public static <K, V> SortedMap<K, V> filterKeys( SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) { - // TODO(user): Return a subclass of Maps.FilteredKeyMap for slightly better + // TODO: Return a subclass of Maps.FilteredKeyMap for slightly better // performance. - return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate)); - } - - /** - * Returns a bimap containing the mappings in {@code unfiltered} whose keys satisfy a predicate. - * The returned bimap is a live view of {@code unfiltered}; changes to one affect the other. - * - * <p>The resulting bimap'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 - * bimap and its views. When given a key that doesn't satisfy the predicate, the bimap's {@code - * put()}, {@code forcePut()} and {@code putAll()} methods throw an {@link - * IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * bimap or its views, only mappings that satisfy the filter will be removed from the underlying - * bimap. - * - * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every key in - * the underlying bimap and determine which satisfy the filter. When a live view is <i>not</i> - * needed, it may be faster to copy the filtered bimap and use the copy. - * - * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as - * documented at {@link Predicate#apply}. - * - * @since 14.0 - */ - public static <K, V> BiMap<K, V> filterKeys( - BiMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) { checkNotNull(keyPredicate); - return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate)); + Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() { + @Override + public boolean apply(Entry<K, V> input) { + return keyPredicate.apply(input.getKey()); + } + }; + return filterEntries(unfiltered, entryPredicate); } /** @@ -1772,10 +1377,16 @@ public final class Maps { Map<K, V> unfiltered, final Predicate<? super V> valuePredicate) { if (unfiltered instanceof SortedMap) { return filterValues((SortedMap<K, V>) unfiltered, valuePredicate); - } else if (unfiltered instanceof BiMap) { - return filterValues((BiMap<K, V>) unfiltered, valuePredicate); } - return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate)); + checkNotNull(valuePredicate); + Predicate<Entry<K, V>> entryPredicate = + new Predicate<Entry<K, V>>() { + @Override + public boolean apply(Entry<K, V> input) { + return valuePredicate.apply(input.getValue()); + } + }; + return filterEntries(unfiltered, entryPredicate); } /** @@ -1809,42 +1420,18 @@ public final class Maps { * * @since 11.0 */ + @Beta public static <K, V> SortedMap<K, V> filterValues( SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) { - return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate)); - } - - /** - * Returns a bimap containing the mappings in {@code unfiltered} whose values satisfy a - * predicate. The returned bimap is a live view of {@code unfiltered}; changes to one affect the - * other. - * - * <p>The resulting bimap'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 - * bimap and its views. When given a value that doesn't satisfy the predicate, the bimap's - * {@code put()}, {@code forcePut()} and {@code putAll()} methods throw an {@link - * IllegalArgumentException}. Similarly, the map's entries have a {@link Entry#setValue} method - * that throws an {@link IllegalArgumentException} when the provided value doesn't satisfy the - * predicate. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * bimap or its views, only mappings that satisfy the filter will be removed from the underlying - * bimap. - * - * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every value in - * the underlying bimap and determine which satisfy the filter. When a live view is <i>not</i> - * needed, it may be faster to copy the filtered bimap and use the copy. - * - * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as - * documented at {@link Predicate#apply}. - * - * @since 14.0 - */ - public static <K, V> BiMap<K, V> filterValues( - BiMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) { - return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate)); + checkNotNull(valuePredicate); + Predicate<Entry<K, V>> entryPredicate = + new Predicate<Entry<K, V>>() { + @Override + public boolean apply(Entry<K, V> input) { + return valuePredicate.apply(input.getValue()); + } + }; + return filterEntries(unfiltered, entryPredicate); } /** @@ -1880,8 +1467,6 @@ public final class Maps { Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { if (unfiltered instanceof SortedMap) { return filterEntries((SortedMap<K, V>) unfiltered, entryPredicate); - } else if (unfiltered instanceof BiMap) { - return filterEntries((BiMap<K, V>) unfiltered, entryPredicate); } checkNotNull(entryPredicate); return (unfiltered instanceof AbstractFilteredMap) @@ -1920,15 +1505,10 @@ public final class Maps { * * @since 11.0 */ + @Beta public static <K, V> SortedMap<K, V> filterEntries( SortedMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { - return Platform.mapsFilterSortedMap(unfiltered, entryPredicate); - } - - static <K, V> SortedMap<K, V> filterSortedIgnoreNavigable( - SortedMap<K, V> unfiltered, - Predicate<? super Entry<K, V>> entryPredicate) { checkNotNull(entryPredicate); return (unfiltered instanceof FilteredEntrySortedMap) ? filterFiltered((FilteredEntrySortedMap<K, V>) unfiltered, entryPredicate) @@ -1936,42 +1516,6 @@ public final class Maps { } /** - * Returns a bimap containing the mappings in {@code unfiltered} that satisfy a predicate. The - * returned bimap is a live view of {@code unfiltered}; changes to one affect the other. - * - * <p>The resulting bimap'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 bimap - * and its views. When given a key/value pair that doesn't satisfy the predicate, the bimap's - * {@code put()}, {@code forcePut()} and {@code putAll()} methods throw an - * {@link IllegalArgumentException}. Similarly, the map's entries have an {@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 - * bimap or its views, only mappings that satisfy the filter will be removed from the underlying - * bimap. - * - * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying bimap and determine which satisfy the filter. When a live - * view is <i>not</i> needed, it may be faster to copy the filtered bimap and use the copy. - * - * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as - * documented at {@link Predicate#apply}. - * - * @since 14.0 - */ - public static <K, V> BiMap<K, V> filterEntries( - BiMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { - checkNotNull(unfiltered); - checkNotNull(entryPredicate); - return (unfiltered instanceof FilteredEntryBiMap) - ? filterFiltered((FilteredEntryBiMap<K, V>) unfiltered, entryPredicate) - : new FilteredEntryBiMap<K, V>(unfiltered, entryPredicate); - } - - /** * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when * filtering a filtered map. */ @@ -2116,7 +1660,6 @@ public final class Maps { } } } - /** * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when * filtering a filtered sorted map. @@ -2177,66 +1720,6 @@ public final class Maps { } } - /** - * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when - * filtering a filtered map. - */ - private static <K, V> BiMap<K, V> filterFiltered( - FilteredEntryBiMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) { - Predicate<Entry<K, V>> predicate = Predicates.and(map.predicate, entryPredicate); - return new FilteredEntryBiMap<K, V>(map.unfiltered(), predicate); - } - - static final class FilteredEntryBiMap<K, V> extends FilteredEntryMap<K, V> - implements BiMap<K, V> { - private final BiMap<V, K> inverse; - - private static <K, V> Predicate<Entry<V, K>> inversePredicate( - final Predicate<? super Entry<K, V>> forwardPredicate) { - return new Predicate<Entry<V, K>>() { - @Override - public boolean apply(Entry<V, K> input) { - return forwardPredicate.apply( - Maps.immutableEntry(input.getValue(), input.getKey())); - } - }; - } - - FilteredEntryBiMap(BiMap<K, V> delegate, - Predicate<? super Entry<K, V>> predicate) { - super(delegate, predicate); - this.inverse = new FilteredEntryBiMap<V, K>( - delegate.inverse(), inversePredicate(predicate), this); - } - - private FilteredEntryBiMap( - BiMap<K, V> delegate, Predicate<? super Entry<K, V>> predicate, - BiMap<V, K> inverse) { - super(delegate, predicate); - this.inverse = inverse; - } - - BiMap<K, V> unfiltered() { - return (BiMap<K, V>) unfiltered; - } - - @Override - public V forcePut(@Nullable K key, @Nullable V value) { - checkArgument(predicate.apply(Maps.immutableEntry(key, value))); - return unfiltered().forcePut(key, value); - } - - @Override - public BiMap<V, K> inverse() { - return inverse; - } - - @Override - public Set<V> values() { - return inverse.keySet(); - } - } - private static class FilteredKeyMap<K, V> extends AbstractFilteredMap<K, V> { Predicate<? super K> keyPredicate; @@ -2328,14 +1811,10 @@ public final class Maps { @Override public Set<K> keySet() { Set<K> result = keySet; - return (result == null) ? keySet = createKeySet() : result; - } - - Set<K> createKeySet() { - return new KeySet(); + return (result == null) ? keySet = new KeySet() : result; } - private class KeySet extends Sets.ImprovedAbstractSet<K> { + private class KeySet extends AbstractSet<K> { @Override public Iterator<K> iterator() { final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator(); return new UnmodifiableIterator<K>() { @@ -2371,13 +1850,22 @@ public final class Maps { 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 (predicate.apply(entry) && !collection.contains(entry.getKey())) { + if (!collection.contains(entry.getKey()) && predicate.apply(entry)) { iterator.remove(); changed = true; } @@ -2396,10 +1884,6 @@ public final class Maps { } } - @Nullable private static <K, V> Entry<K, V> unmodifiableOrNull(@Nullable Entry<K, V> entry) { - return (entry == null) ? null : Maps.unmodifiableEntry(entry); - } - /** * {@code AbstractMap} extension that implements {@link #isEmpty()} as {@code * entrySet().isEmpty()} instead of {@code size() == 0} to speed up @@ -2408,7 +1892,7 @@ public final class Maps { * implementation. */ @GwtCompatible - abstract static class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> { + static abstract 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} @@ -2445,7 +1929,7 @@ public final class Maps { @Override public Collection<V> values() { Collection<V> result = values; if (result == null) { - return values = new Values<K, V>() { + return values = new Values<K, V>(){ @Override Map<K, V> map() { return ImprovedAbstractMap.this; } @@ -2453,6 +1937,17 @@ public final class Maps { } 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 STANDARD_JOINER = @@ -2460,46 +1955,25 @@ public final class Maps { /** * Delegates to {@link Map#get}. Returns {@code null} on {@code - * ClassCastException} and {@code NullPointerException}. + * ClassCastException}. */ static <V> V safeGet(Map<?, V> map, Object key) { - checkNotNull(map); try { return map.get(key); } catch (ClassCastException e) { return null; - } catch (NullPointerException e) { - return null; } } /** * Delegates to {@link Map#containsKey}. Returns {@code false} on {@code - * ClassCastException} and {@code NullPointerException}. + * ClassCastException} */ static boolean safeContainsKey(Map<?, ?> map, Object key) { - checkNotNull(map); try { return map.containsKey(key); } catch (ClassCastException e) { return false; - } catch (NullPointerException e) { - return false; - } - } - - /** - * Delegates to {@link Map#remove}. Returns {@code null} on {@code - * ClassCastException} and {@code NullPointerException}. - */ - static <V> V safeRemove(Map<?, V> map, Object key) { - checkNotNull(map); - try { - return map.remove(key); - } catch (ClassCastException e) { - return null; - } catch (NullPointerException e) { - return null; } } @@ -2558,6 +2032,13 @@ public final class Maps { } /** + * An implementation of {@link Map#hashCode}. + */ + static int hashCodeImpl(Map<?, ?> map) { + return Sets.hashCodeImpl(map.entrySet()); + } + + /** * An implementation of {@link Map#toString}. */ static String toStringImpl(Map<?, ?> map) { @@ -2581,30 +2062,36 @@ public final class Maps { * An admittedly inefficient implementation of {@link Map#containsKey}. */ static boolean containsKeyImpl(Map<?, ?> map, @Nullable Object key) { - return Iterators.contains(keyIterator(map.entrySet().iterator()), key); + for (Entry<?, ?> entry : map.entrySet()) { + if (Objects.equal(entry.getKey(), key)) { + return true; + } + } + return false; } /** * An implementation of {@link Map#containsValue}. */ static boolean containsValueImpl(Map<?, ?> map, @Nullable Object value) { - return Iterators.contains(valueIterator(map.entrySet().iterator()), value); - } - - static <K, V> Iterator<K> keyIterator(Iterator<Entry<K, V>> entryIterator) { - return new TransformedIterator<Entry<K, V>, K>(entryIterator) { - @Override - K transform(Entry<K, V> entry) { - return entry.getKey(); + for (Entry<?, ?> entry : map.entrySet()) { + if (Objects.equal(entry.getValue(), value)) { + return true; } - }; + } + return false; } - abstract static class KeySet<K, V> extends Sets.ImprovedAbstractSet<K> { + abstract static class KeySet<K, V> extends AbstractSet<K> { abstract Map<K, V> map(); @Override public Iterator<K> iterator() { - return keyIterator(map().entrySet().iterator()); + return Iterators.transform(map().entrySet().iterator(), + new Function<Map.Entry<K, V>, K>() { + @Override public K apply(Entry<K, V> entry) { + return entry.getKey(); + } + }); } @Override public int size() { @@ -2627,50 +2114,27 @@ public final class Maps { return false; } + @Override + public boolean removeAll(Collection<?> c) { + // TODO(user): find out why this is necessary to make GWT tests pass. + return super.removeAll(checkNotNull(c)); + } + @Override public void clear() { map().clear(); } } - @Nullable - static <K> K keyOrNull(@Nullable Entry<K, ?> entry) { - return (entry == null) ? null : entry.getKey(); - } - - @Nullable - static <V> V valueOrNull(@Nullable Entry<?, V> entry) { - return (entry == null) ? null : entry.getValue(); - } - - static <K, V> Iterator<V> valueIterator(Iterator<Entry<K, V>> entryIterator) { - return new TransformedIterator<Entry<K, V>, V>(entryIterator) { - @Override - V transform(Entry<K, V> entry) { - return entry.getValue(); - } - }; - } - - static <K, V> UnmodifiableIterator<V> valueIterator( - final UnmodifiableIterator<Entry<K, V>> entryIterator) { - return new UnmodifiableIterator<V>() { - @Override - public boolean hasNext() { - return entryIterator.hasNext(); - } - - @Override - public V next() { - return entryIterator.next().getValue(); - } - }; - } - abstract static class Values<K, V> extends AbstractCollection<V> { abstract Map<K, V> map(); @Override public Iterator<V> iterator() { - return valueIterator(map().entrySet().iterator()); + return Iterators.transform(map().entrySet().iterator(), + new Function<Entry<K, V>, V>() { + @Override public V apply(Entry<K, V> entry) { + return entry.getValue(); + } + }); } @Override public boolean remove(Object o) { @@ -2732,8 +2196,7 @@ public final class Maps { } } - abstract static class EntrySet<K, V> - extends Sets.ImprovedAbstractSet<Entry<K, V>> { + abstract static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> { abstract Map<K, V> map(); @Override public int size() { |