diff options
Diffstat (limited to 'guava/src/com/google/common/collect/Maps.java')
-rw-r--r-- | guava/src/com/google/common/collect/Maps.java | 2126 |
1 files changed, 193 insertions, 1933 deletions
diff --git a/guava/src/com/google/common/collect/Maps.java b/guava/src/com/google/common/collect/Maps.java index 9569a52..4215869 100644 --- a/guava/src/com/google/common/collect/Maps.java +++ b/guava/src/com/google/common/collect/Maps.java @@ -23,6 +23,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; 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; @@ -35,6 +36,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,25 +48,17 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.NavigableMap; -import java.util.NavigableSet; import java.util.Properties; 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 @@ -76,60 +70,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. * @@ -285,9 +225,9 @@ public final class Maps { * @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 + public static <K, V> TreeMap<K, V> newTreeMap( + @Nullable Comparator<? super K> comparator) { + // Ideally, the "? super" 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; @@ -329,6 +269,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. @@ -352,7 +324,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()); } /** @@ -524,7 +496,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()) @@ -561,6 +533,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); @@ -645,484 +618,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); - } - - /** - * Returns a view of the navigable 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 - @GwtIncompatible("NavigableMap") - public static <K, V> NavigableMap<K, V> asMap( - NavigableSet<K> set, Function<? super K, V> function) { - return new NavigableAsMapView<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(); - } - } - - @GwtIncompatible("NavigableMap") - private static final class NavigableAsMapView<K, V> - extends AbstractNavigableMap<K, V> { - /* - * Using AbstractNavigableMap is simpler than extending SortedAsMapView and rewriting all the - * NavigableMap methods. - */ - - private final NavigableSet<K> set; - private final Function<? super K, V> function; - - NavigableAsMapView(NavigableSet<K> ks, Function<? super K, V> vFunction) { - this.set = checkNotNull(ks); - this.function = checkNotNull(vFunction); - } - - @Override - public NavigableMap<K, V> subMap( - K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { - return asMap(set.subSet(fromKey, fromInclusive, toKey, toInclusive), function); - } - - @Override - public NavigableMap<K, V> headMap(K toKey, boolean inclusive) { - return asMap(set.headSet(toKey, inclusive), function); - } - - @Override - public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) { - return asMap(set.tailSet(fromKey, inclusive), function); - } - - @Override - public Comparator<? super K> comparator() { - return set.comparator(); - } - - @Override - @Nullable - public V get(@Nullable Object key) { - if (set.contains(key)) { - @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it - K k = (K) key; - return function.apply(k); - } else { - return null; - } - } - - @Override - public void clear() { - set.clear(); - } - - @Override - Iterator<Entry<K, V>> entryIterator() { - return asSetEntryIterator(set, function); - } - - @Override - Iterator<Entry<K, V>> descendingEntryIterator() { - return descendingMap().entrySet().iterator(); - } - - @Override - public NavigableSet<K> navigableKeySet() { - return removeOnlyNavigableSet(set); - } - - @Override - public int size() { - return set.size(); - } - - @Override - public NavigableMap<K, V> descendingMap() { - return asMap(set.descendingSet(), function); - } - } - - 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)); - } - }; - } - - @GwtIncompatible("NavigableSet") - private static <E> NavigableSet<E> removeOnlyNavigableSet(final NavigableSet<E> set) { - return new ForwardingNavigableSet<E>() { - @Override - protected NavigableSet<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)); - } - - @Override - public NavigableSet<E> headSet(E toElement, boolean inclusive) { - return removeOnlyNavigableSet(super.headSet(toElement, inclusive)); - } - - @Override - public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { - return removeOnlyNavigableSet(super.tailSet(fromElement, inclusive)); - } - - @Override - public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, - E toElement, boolean toInclusive) { - return removeOnlyNavigableSet(super.subSet( - fromElement, fromInclusive, toElement, toInclusive)); - } - - @Override - public NavigableSet<E> descendingSet() { - return removeOnlyNavigableSet(super.descendingSet()); - } - }; - } - - /** - * 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 @@ -1143,6 +638,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. @@ -1330,38 +843,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 @@ -1384,7 +865,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, @@ -1458,8 +939,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); } /** @@ -1501,67 +990,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)); - } - - /** - * Returns a view of a navigable 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 - * - * NavigableMap<String, Integer> map = Maps.newTreeMap(); - * map.put("a", 4); - * map.put("b", 9); - * Function<Integer, Double> sqrt = - * new Function<Integer, Double>() { - * public Double apply(Integer in) { - * return Math.sqrt((int) in); - * } - * }; - * NavigableMap<String, Double> transformed = - * Maps.transformNavigableValues(map, sqrt); - * System.out.println(transformed);}</pre> - * - * ... prints {@code {a=2.0, b=3.0}}. - * - * 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. - * - * @since 13.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V1, V2> NavigableMap<K, V2> transformValues( - NavigableMap<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); } /** @@ -1676,74 +1116,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); - } - - /** - * Returns a view of a navigable map whose values are derived from the - * original navigable map's entries. In contrast to {@link - * #transformValues}, this method's entry-transformation logic may - * depend on the key as well as the value. - * - * <p>All other properties of the transformed map, such as iteration order, - * are left intact. For example, the code: <pre> {@code - * - * NavigableMap<String, Boolean> options = Maps.newTreeMap(); - * options.put("verbose", false); - * options.put("sort", true); - * EntryTransformer<String, Boolean, String> flagPrefixer = - * new EntryTransformer<String, Boolean, String>() { - * public String transformEntry(String key, Boolean value) { - * return value ? key : ("yes" + key); - * } - * }; - * NavigableMap<String, String> transformed = - * LabsMaps.transformNavigableEntries(options, flagPrefixer); - * System.out.println(transformed);}</pre> - * - * ... prints {@code {sort=yessort, verbose=verbose}}. - * - * <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 null - * values provided that the transformer is capable of accepting null inputs. - * The transformed map might contain null values if the transformer sometimes - * gives a null result. - * - * <p>The returned map is not thread-safe or serializable, even if the - * underlying map is. - * - * <p>The transformer is applied lazily, invoked when needed. This is - * necessary for the returned map to be a view, but it means that the - * transformer will be applied many times for bulk operations like {@link - * Map#containsValue} and {@link Object#toString}. For this to perform well, - * {@code transformer} 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. - * - * <p><b>Warning:</b> This method assumes that for any instance {@code k} of - * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies - * that {@code k2} is also of type {@code K}. Using an {@code - * EntryTransformer} key type for which this may not hold, such as {@code - * ArrayList}, may risk a {@code ClassCastException} when calling methods on - * the transformed map. - * - * @since 13.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V1, V2> NavigableMap<K, V2> transformEntries( - final NavigableMap<K, V1> fromMap, - EntryTransformer<? super K, ? super V1, V2> transformer) { - return new TransformedEntriesNavigableMap<K, V1, V2>(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); } @@ -1835,23 +1210,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()); - } - }; - } - }; + }); } }; } @@ -1909,144 +1278,7 @@ public final class Maps { @Override public SortedMap<K, V2> tailMap(K fromKey) { return transformEntries(fromMap().tailMap(fromKey), transformer); } - } - - @GwtIncompatible("NavigableMap") - private static class TransformedEntriesNavigableMap<K, V1, V2> - extends TransformedEntriesSortedMap<K, V1, V2> - implements NavigableMap<K, V2> { - - TransformedEntriesNavigableMap(NavigableMap<K, V1> fromMap, - EntryTransformer<? super K, ? super V1, V2> transformer) { - super(fromMap, transformer); - } - - @Override public Entry<K, V2> ceilingEntry(K key) { - return transformEntry(fromMap().ceilingEntry(key)); - } - - @Override public K ceilingKey(K key) { - return fromMap().ceilingKey(key); - } - - @Override public NavigableSet<K> descendingKeySet() { - return fromMap().descendingKeySet(); - } - - @Override public NavigableMap<K, V2> descendingMap() { - return transformEntries(fromMap().descendingMap(), transformer); - } - - @Override public Entry<K, V2> firstEntry() { - return transformEntry(fromMap().firstEntry()); - } - @Override public Entry<K, V2> floorEntry(K key) { - return transformEntry(fromMap().floorEntry(key)); - } - - @Override public K floorKey(K key) { - return fromMap().floorKey(key); - } - - @Override public NavigableMap<K, V2> headMap(K toKey) { - return headMap(toKey, false); - } - - @Override public NavigableMap<K, V2> headMap(K toKey, boolean inclusive) { - return transformEntries( - fromMap().headMap(toKey, inclusive), transformer); - } - - @Override public Entry<K, V2> higherEntry(K key) { - return transformEntry(fromMap().higherEntry(key)); - } - - @Override public K higherKey(K key) { - return fromMap().higherKey(key); - } - - @Override public Entry<K, V2> lastEntry() { - return transformEntry(fromMap().lastEntry()); - } - - @Override public Entry<K, V2> lowerEntry(K key) { - return transformEntry(fromMap().lowerEntry(key)); - } - @Override public K lowerKey(K key) { - return fromMap().lowerKey(key); - } - - @Override public NavigableSet<K> navigableKeySet() { - return fromMap().navigableKeySet(); - } - - @Override public Entry<K, V2> pollFirstEntry() { - return transformEntry(fromMap().pollFirstEntry()); - } - - @Override public Entry<K, V2> pollLastEntry() { - return transformEntry(fromMap().pollLastEntry()); - } - - @Override public NavigableMap<K, V2> subMap( - K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { - return transformEntries( - fromMap().subMap(fromKey, fromInclusive, toKey, toInclusive), - transformer); - } - - @Override public NavigableMap<K, V2> subMap(K fromKey, K toKey) { - return subMap(fromKey, true, toKey, false); - } - - @Override public NavigableMap<K, V2> tailMap(K fromKey) { - return tailMap(fromKey, true); - } - - @Override public NavigableMap<K, V2> tailMap(K fromKey, boolean inclusive) { - return transformEntries( - fromMap().tailMap(fromKey, inclusive), transformer); - } - - private Entry<K, V2> transformEntry(Entry<K, V1> entry) { - if (entry == null) { - return null; - } - K key = entry.getKey(); - V2 v2 = transformer.transformEntry(key, entry.getValue()); - return Maps.immutableEntry(key, v2); - } - - @Override protected NavigableMap<K, V1> fromMap() { - return (NavigableMap<K, V1>) super.fromMap(); - } - } - - 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()); - } } /** @@ -2081,11 +1313,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>( @@ -2122,80 +1358,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 - // performance. - return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate)); - } - - /** - * Returns a navigable 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. When given a key that - * doesn't satisfy the predicate, the map's {@code put()} and {@code putAll()} - * methods throw an {@link IllegalArgumentException}. - * - * <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. - * - * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with - * equals</i>, as documented at {@link Predicate#apply}. Do not provide a - * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is - * inconsistent with equals. - * - * @since 14.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V> NavigableMap<K, V> filterKeys( - NavigableMap<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); } /** @@ -2231,10 +1406,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); } /** @@ -2268,79 +1449,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 navigable 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. When given a value - * that doesn't satisfy the predicate, the map's {@code put()}, {@code - * putAll()}, and {@link Entry#setValue} methods throw an {@link - * IllegalArgumentException}. - * - * <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. - * - * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with - * equals</i>, as documented at {@link Predicate#apply}. Do not provide a - * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is - * inconsistent with equals. - * - * @since 14.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V> NavigableMap<K, V> filterValues( - NavigableMap<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); } /** @@ -2376,8 +1496,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) @@ -2416,15 +1534,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) @@ -2432,83 +1545,6 @@ public final class Maps { } /** - * Returns a sorted 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. When given a - * key/value pair that doesn't satisfy the predicate, the map's {@code put()} - * 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 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. - * - * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with - * equals</i>, as documented at {@link Predicate#apply}. - * - * @since 14.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V> NavigableMap<K, V> filterEntries( - NavigableMap<K, V> unfiltered, - Predicate<? super Entry<K, V>> entryPredicate) { - checkNotNull(entryPredicate); - return (unfiltered instanceof FilteredEntryNavigableMap) - ? filterFiltered((FilteredEntryNavigableMap<K, V>) unfiltered, entryPredicate) - : new FilteredEntryNavigableMap<K, V>(checkNotNull(unfiltered), entryPredicate); - } - - /** - * 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. */ @@ -2653,7 +1689,6 @@ public final class Maps { } } } - /** * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when * filtering a filtered sorted map. @@ -2714,251 +1749,6 @@ public final class Maps { } } - /** - * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when - * filtering a filtered navigable map. - */ - @GwtIncompatible("NavigableMap") - private static <K, V> NavigableMap<K, V> filterFiltered( - FilteredEntryNavigableMap<K, V> map, - Predicate<? super Entry<K, V>> entryPredicate) { - Predicate<Entry<K, V>> predicate - = Predicates.and(map.predicate, entryPredicate); - return new FilteredEntryNavigableMap<K, V>(map.sortedMap(), predicate); - } - - @GwtIncompatible("NavigableMap") - private static class FilteredEntryNavigableMap<K, V> extends FilteredEntrySortedMap<K, V> - implements NavigableMap<K, V> { - - FilteredEntryNavigableMap( - NavigableMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { - super(unfiltered, entryPredicate); - } - - @Override - NavigableMap<K, V> sortedMap() { - return (NavigableMap<K, V>) super.sortedMap(); - } - - @Override - public Entry<K, V> lowerEntry(K key) { - return headMap(key, false).lastEntry(); - } - - @Override - public K lowerKey(K key) { - return keyOrNull(lowerEntry(key)); - } - - @Override - public Entry<K, V> floorEntry(K key) { - return headMap(key, true).lastEntry(); - } - - @Override - public K floorKey(K key) { - return keyOrNull(floorEntry(key)); - } - - @Override - public Entry<K, V> ceilingEntry(K key) { - return tailMap(key, true).firstEntry(); - } - - @Override - public K ceilingKey(K key) { - return keyOrNull(ceilingEntry(key)); - } - - @Override - public Entry<K, V> higherEntry(K key) { - return tailMap(key, false).firstEntry(); - } - - @Override - public K higherKey(K key) { - return keyOrNull(higherEntry(key)); - } - - @Override - public Entry<K, V> firstEntry() { - return Iterables.getFirst(entrySet(), null); - } - - @Override - public Entry<K, V> lastEntry() { - return Iterables.getFirst(descendingMap().entrySet(), null); - } - - @Override - public Entry<K, V> pollFirstEntry() { - return pollFirstSatisfyingEntry(sortedMap().entrySet().iterator()); - } - - @Override - public Entry<K, V> pollLastEntry() { - return pollFirstSatisfyingEntry(sortedMap().descendingMap().entrySet().iterator()); - } - - @Nullable - Entry<K, V> pollFirstSatisfyingEntry(Iterator<Entry<K, V>> entryIterator) { - while (entryIterator.hasNext()) { - Entry<K, V> entry = entryIterator.next(); - if (predicate.apply(entry)) { - entryIterator.remove(); - return entry; - } - } - return null; - } - - @Override - public NavigableMap<K, V> descendingMap() { - return filterEntries(sortedMap().descendingMap(), predicate); - } - - @Override - public NavigableSet<K> keySet() { - return (NavigableSet<K>) super.keySet(); - } - - @Override - NavigableSet<K> createKeySet() { - return new NavigableKeySet<K, V>(this) { - @Override - public boolean removeAll(Collection<?> c) { - boolean changed = false; - Iterator<Entry<K, V>> entryIterator = sortedMap().entrySet().iterator(); - while (entryIterator.hasNext()) { - Entry<K, V> entry = entryIterator.next(); - if (c.contains(entry.getKey()) && predicate.apply(entry)) { - entryIterator.remove(); - changed = true; - } - } - return changed; - } - - @Override - public boolean retainAll(Collection<?> c) { - boolean changed = false; - Iterator<Entry<K, V>> entryIterator = sortedMap().entrySet().iterator(); - while (entryIterator.hasNext()) { - Entry<K, V> entry = entryIterator.next(); - if (!c.contains(entry.getKey()) && predicate.apply(entry)) { - entryIterator.remove(); - changed = true; - } - } - return changed; - } - }; - } - - @Override - public NavigableSet<K> navigableKeySet() { - return keySet(); - } - - @Override - public NavigableSet<K> descendingKeySet() { - return descendingMap().navigableKeySet(); - } - - @Override - public NavigableMap<K, V> subMap(K fromKey, K toKey) { - return subMap(fromKey, true, toKey, false); - } - - @Override - public NavigableMap<K, V> subMap( - K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { - return filterEntries( - sortedMap().subMap(fromKey, fromInclusive, toKey, toInclusive), predicate); - } - - @Override - public NavigableMap<K, V> headMap(K toKey) { - return headMap(toKey, false); - } - - @Override - public NavigableMap<K, V> headMap(K toKey, boolean inclusive) { - return filterEntries(sortedMap().headMap(toKey, inclusive), predicate); - } - - @Override - public NavigableMap<K, V> tailMap(K fromKey) { - return tailMap(fromKey, true); - } - - @Override - public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) { - return filterEntries(sortedMap().tailMap(fromKey, inclusive), predicate); - } - } - - /** - * 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; @@ -3050,14 +1840,10 @@ public final class Maps { @Override public Set<K> keySet() { Set<K> result = keySet; - return (result == null) ? keySet = createKeySet() : result; + return (result == null) ? keySet = new KeySet() : result; } - Set<K> createKeySet() { - return new KeySet(); - } - - 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>() { @@ -3093,13 +1879,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; } @@ -3119,224 +1914,6 @@ public final class Maps { } /** - * Returns an unmodifiable view of the specified navigable map. Query operations on the returned - * map read through to the specified map, and attempts to modify the returned map, whether direct - * or via its views, result in an {@code UnsupportedOperationException}. - * - * <p>The returned navigable map will be serializable if the specified navigable map is - * serializable. - * - * @param map the navigable map for which an unmodifiable view is to be returned - * @return an unmodifiable view of the specified navigable map - * @since 12.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V> NavigableMap<K, V> unmodifiableNavigableMap(NavigableMap<K, V> map) { - checkNotNull(map); - if (map instanceof UnmodifiableNavigableMap) { - return map; - } else { - return new UnmodifiableNavigableMap<K, V>(map); - } - } - - @Nullable private static <K, V> Entry<K, V> unmodifiableOrNull(@Nullable Entry<K, V> entry) { - return (entry == null) ? null : Maps.unmodifiableEntry(entry); - } - - @GwtIncompatible("NavigableMap") - static class UnmodifiableNavigableMap<K, V> - extends ForwardingSortedMap<K, V> implements NavigableMap<K, V>, Serializable { - private final NavigableMap<K, V> delegate; - - UnmodifiableNavigableMap(NavigableMap<K, V> delegate) { - this.delegate = delegate; - } - - @Override - protected SortedMap<K, V> delegate() { - return Collections.unmodifiableSortedMap(delegate); - } - - @Override - public Entry<K, V> lowerEntry(K key) { - return unmodifiableOrNull(delegate.lowerEntry(key)); - } - - @Override - public K lowerKey(K key) { - return delegate.lowerKey(key); - } - - @Override - public Entry<K, V> floorEntry(K key) { - return unmodifiableOrNull(delegate.floorEntry(key)); - } - - @Override - public K floorKey(K key) { - return delegate.floorKey(key); - } - - @Override - public Entry<K, V> ceilingEntry(K key) { - return unmodifiableOrNull(delegate.ceilingEntry(key)); - } - - @Override - public K ceilingKey(K key) { - return delegate.ceilingKey(key); - } - - @Override - public Entry<K, V> higherEntry(K key) { - return unmodifiableOrNull(delegate.higherEntry(key)); - } - - @Override - public K higherKey(K key) { - return delegate.higherKey(key); - } - - @Override - public Entry<K, V> firstEntry() { - return unmodifiableOrNull(delegate.firstEntry()); - } - - @Override - public Entry<K, V> lastEntry() { - return unmodifiableOrNull(delegate.lastEntry()); - } - - @Override - public final Entry<K, V> pollFirstEntry() { - throw new UnsupportedOperationException(); - } - - @Override - public final Entry<K, V> pollLastEntry() { - throw new UnsupportedOperationException(); - } - - private transient UnmodifiableNavigableMap<K, V> descendingMap; - - @Override - public NavigableMap<K, V> descendingMap() { - UnmodifiableNavigableMap<K, V> result = descendingMap; - if (result == null) { - descendingMap = result = new UnmodifiableNavigableMap<K, V>(delegate.descendingMap()); - result.descendingMap = this; - } - return result; - } - - @Override - public Set<K> keySet() { - return navigableKeySet(); - } - - @Override - public NavigableSet<K> navigableKeySet() { - return Sets.unmodifiableNavigableSet(delegate.navigableKeySet()); - } - - @Override - public NavigableSet<K> descendingKeySet() { - return Sets.unmodifiableNavigableSet(delegate.descendingKeySet()); - } - - @Override - public SortedMap<K, V> subMap(K fromKey, K toKey) { - return subMap(fromKey, true, toKey, false); - } - - @Override - public SortedMap<K, V> headMap(K toKey) { - return headMap(toKey, false); - } - - @Override - public SortedMap<K, V> tailMap(K fromKey) { - return tailMap(fromKey, true); - } - - @Override - public - NavigableMap<K, V> - subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { - return Maps.unmodifiableNavigableMap(delegate.subMap( - fromKey, - fromInclusive, - toKey, - toInclusive)); - } - - @Override - public NavigableMap<K, V> headMap(K toKey, boolean inclusive) { - return Maps.unmodifiableNavigableMap(delegate.headMap(toKey, inclusive)); - } - - @Override - public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) { - return Maps.unmodifiableNavigableMap(delegate.tailMap(fromKey, inclusive)); - } - } - - /** - * Returns a synchronized (thread-safe) navigable map backed by the specified - * navigable map. In order to guarantee serial access, it is critical that - * <b>all</b> access to the backing navigable map is accomplished - * through the returned navigable map (or its views). - * - * <p>It is imperative that the user manually synchronize on the returned - * navigable map when iterating over any of its collection views, or the - * collections views of any of its {@code descendingMap}, {@code subMap}, - * {@code headMap} or {@code tailMap} views. <pre> {@code - * - * NavigableMap<K, V> map = synchronizedNavigableMap(new TreeMap<K, V>()); - * - * // Needn't be in synchronized block - * NavigableSet<K> set = map.navigableKeySet(); - * - * synchronized (map) { // Synchronizing on map, not set! - * Iterator<K> it = set.iterator(); // Must be in synchronized block - * while (it.hasNext()){ - * foo(it.next()); - * } - * }}</pre> - * - * or: <pre> {@code - * - * NavigableMap<K, V> map = synchronizedNavigableMap(new TreeMap<K, V>()); - * NavigableMap<K, V> map2 = map.subMap(foo, false, bar, true); - * - * // Needn't be in synchronized block - * NavigableSet<K> set2 = map2.descendingKeySet(); - * - * synchronized (map) { // Synchronizing on map, not map2 or set2! - * Iterator<K> it = set2.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 navigable map will be serializable if the specified - * navigable map is serializable. - * - * @param navigableMap the navigable map to be "wrapped" in a synchronized - * navigable map. - * @return a synchronized view of the specified navigable map. - * @since 13.0 - */ - @GwtIncompatible("NavigableMap") - public static <K, V> NavigableMap<K, V> synchronizedNavigableMap( - NavigableMap<K, V> navigableMap) { - return Synchronized.navigableMap(navigableMap); - } - - /** * {@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 @@ -3344,7 +1921,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} @@ -3381,7 +1958,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; } @@ -3389,6 +1966,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 = @@ -3396,46 +1984,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; } } @@ -3494,6 +2061,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) { @@ -3517,30 +2091,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() { @@ -3563,153 +2143,27 @@ public final class Maps { return false; } - @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(); - } - - @GwtIncompatible("NavigableMap") - static class NavigableKeySet<K, V> extends KeySet<K, V> implements NavigableSet<K> { - private final NavigableMap<K, V> map; - - NavigableKeySet(NavigableMap<K, V> map) { - this.map = checkNotNull(map); - } - - @Override - NavigableMap<K, V> map() { - return map; - } - - @Override - public Comparator<? super K> comparator() { - return map().comparator(); - } - - @Override - public K first() { - return map().firstKey(); - } - - @Override - public K last() { - return map().lastKey(); - } - - @Override - public K lower(K e) { - return map().lowerKey(e); - } - - @Override - public K floor(K e) { - return map().floorKey(e); - } - - @Override - public K ceiling(K e) { - return map().ceilingKey(e); - } - - @Override - public K higher(K e) { - return map().higherKey(e); - } - - @Override - public K pollFirst() { - return keyOrNull(map().pollFirstEntry()); - } - - @Override - public K pollLast() { - return keyOrNull(map().pollLastEntry()); - } - - @Override - public NavigableSet<K> descendingSet() { - return map().descendingKeySet(); - } - - @Override - public Iterator<K> descendingIterator() { - return descendingSet().iterator(); - } - - @Override - public NavigableSet<K> subSet( - K fromElement, - boolean fromInclusive, - K toElement, - boolean toInclusive) { - return map().subMap(fromElement, fromInclusive, toElement, toInclusive).navigableKeySet(); - } - - @Override - public NavigableSet<K> headSet(K toElement, boolean inclusive) { - return map().headMap(toElement, inclusive).navigableKeySet(); - } - - @Override - public NavigableSet<K> tailSet(K fromElement, boolean inclusive) { - return map().tailMap(fromElement, inclusive).navigableKeySet(); - } - - @Override - public SortedSet<K> subSet(K fromElement, K toElement) { - return subSet(fromElement, true, toElement, false); - } - @Override - public SortedSet<K> headSet(K toElement) { - return headSet(toElement, false); + 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 SortedSet<K> tailSet(K fromElement) { - return tailSet(fromElement, true); + @Override public void clear() { + map().clear(); } } - 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) { @@ -3771,8 +2225,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() { @@ -3835,197 +2288,4 @@ public final class Maps { } } } - - @GwtIncompatible("NavigableMap") - abstract static class DescendingMap<K, V> extends ForwardingMap<K, V> - implements NavigableMap<K, V> { - - abstract NavigableMap<K, V> forward(); - - @Override - protected final Map<K, V> delegate() { - return forward(); - } - - private transient Comparator<? super K> comparator; - - @SuppressWarnings("unchecked") - @Override - public Comparator<? super K> comparator() { - Comparator<? super K> result = comparator; - if (result == null) { - Comparator<? super K> forwardCmp = forward().comparator(); - if (forwardCmp == null) { - forwardCmp = (Comparator) Ordering.natural(); - } - result = comparator = reverse(forwardCmp); - } - return result; - } - - // If we inline this, we get a javac error. - private static <T> Ordering<T> reverse(Comparator<T> forward) { - return Ordering.from(forward).reverse(); - } - - @Override - public K firstKey() { - return forward().lastKey(); - } - - @Override - public K lastKey() { - return forward().firstKey(); - } - - @Override - public Entry<K, V> lowerEntry(K key) { - return forward().higherEntry(key); - } - - @Override - public K lowerKey(K key) { - return forward().higherKey(key); - } - - @Override - public Entry<K, V> floorEntry(K key) { - return forward().ceilingEntry(key); - } - - @Override - public K floorKey(K key) { - return forward().ceilingKey(key); - } - - @Override - public Entry<K, V> ceilingEntry(K key) { - return forward().floorEntry(key); - } - - @Override - public K ceilingKey(K key) { - return forward().floorKey(key); - } - - @Override - public Entry<K, V> higherEntry(K key) { - return forward().lowerEntry(key); - } - - @Override - public K higherKey(K key) { - return forward().lowerKey(key); - } - - @Override - public Entry<K, V> firstEntry() { - return forward().lastEntry(); - } - - @Override - public Entry<K, V> lastEntry() { - return forward().firstEntry(); - } - - @Override - public Entry<K, V> pollFirstEntry() { - return forward().pollLastEntry(); - } - - @Override - public Entry<K, V> pollLastEntry() { - return forward().pollFirstEntry(); - } - - @Override - public NavigableMap<K, V> descendingMap() { - return forward(); - } - - private transient Set<Entry<K, V>> entrySet; - - @Override - public Set<Entry<K, V>> entrySet() { - Set<Entry<K, V>> result = entrySet; - return (result == null) ? entrySet = createEntrySet() : result; - } - - abstract Iterator<Entry<K, V>> entryIterator(); - - Set<Entry<K, V>> createEntrySet() { - return new EntrySet<K, V>() { - - @Override - Map<K, V> map() { - return DescendingMap.this; - } - - @Override - public Iterator<Entry<K, V>> iterator() { - return entryIterator(); - } - }; - } - - @Override - public Set<K> keySet() { - return navigableKeySet(); - } - - private transient NavigableSet<K> navigableKeySet; - - @Override - public NavigableSet<K> navigableKeySet() { - NavigableSet<K> result = navigableKeySet; - return (result == null) ? navigableKeySet = new NavigableKeySet<K, V>(this) : result; - } - - @Override - public NavigableSet<K> descendingKeySet() { - return forward().navigableKeySet(); - } - - @Override - public - NavigableMap<K, V> - subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { - return forward().subMap(toKey, toInclusive, fromKey, fromInclusive).descendingMap(); - } - - @Override - public NavigableMap<K, V> headMap(K toKey, boolean inclusive) { - return forward().tailMap(toKey, inclusive).descendingMap(); - } - - @Override - public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) { - return forward().headMap(fromKey, inclusive).descendingMap(); - } - - @Override - public SortedMap<K, V> subMap(K fromKey, K toKey) { - return subMap(fromKey, true, toKey, false); - } - - @Override - public SortedMap<K, V> headMap(K toKey) { - return headMap(toKey, false); - } - - @Override - public SortedMap<K, V> tailMap(K fromKey) { - return tailMap(fromKey, true); - } - - @Override - public Collection<V> values() { - return new Values<K, V>() { - @Override - Map<K, V> map() { - return DescendingMap.this; - } - }; - } - } } |