# HG changeset patch
# User mduigou
# Date 1370629512 25200
# Node ID 86df96c425eb045ffd8644d81f01df5c1a5964cc
# Parent f5f54e493a645822aa5fb7a13e15064103f8c5ea
7129185: Add Collections.{checked|empty|unmodifiable}Navigable{Map|Set}
Reviewed-by: dmocek
diff --git a/src/share/classes/java/util/Collections.java b/src/share/classes/java/util/Collections.java
--- a/src/share/classes/java/util/Collections.java
+++ b/src/share/classes/java/util/Collections.java
@@ -27,6 +27,7 @@
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@@ -136,7 +137,7 @@
*
*
The implementation was adapted from Tim Peters's list sort for Python
* (
- * TimSort). It uses techiques from Peter McIlroy's "Optimistic
+ * TimSort). It uses techniques from Peter McIlroy's "Optimistic
* Sorting and Information Theoretic Complexity", in Proceedings of the
* Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
* January 1993.
@@ -197,7 +198,7 @@
*
*
The implementation was adapted from Tim Peters's list sort for Python
* (
- * TimSort). It uses techiques from Peter McIlroy's "Optimistic
+ * TimSort). It uses techniques from Peter McIlroy's "Optimistic
* Sorting and Information Theoretic Complexity", in Proceedings of the
* Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
* January 1993.
@@ -1212,6 +1213,72 @@
}
/**
+ * Returns an unmodifiable view of the specified navigable set. This method
+ * allows modules to provide users with "read-only" access to internal
+ * navigable sets. Query operations on the returned navigable set "read
+ * through" to the specified navigable set. Attempts to modify the returned
+ * navigable set, whether direct, via its iterator, or via its
+ * subSet, headSet, or tailSet views, result in
+ * an UnsupportedOperationException.
+ *
+ * The returned navigable set will be serializable if the specified sorted set
+ * is serializable.
+ *
+ * @param s the navigable set for which an unmodifiable view is to be
+ * returned
+ * @return an unmodifiable view of the specified navigable set
+ * @since 1.8
+ */
+ public static NavigableSet unmodifiableNavigableSet(NavigableSet s) {
+ return new UnmodifiableNavigableSet<>(s);
+ }
+
+ /**
+ * @serial include
+ */
+ static class UnmodifiableNavigableSet
+ extends UnmodifiableSortedSet
+ implements NavigableSet, Serializable {
+
+ private static final long serialVersionUID = -6027448201786391929L;
+
+ private final NavigableSet ns;
+
+ UnmodifiableNavigableSet(NavigableSet s) {super(s); ns = s;}
+
+ @Override public E lower(E e) { return ns.lower(e); }
+ @Override public E floor(E e) { return ns.floor(e); }
+ @Override public E ceiling(E e) { return ns.ceiling(e); }
+ @Override public E higher(E e) { return ns.higher(e); }
+ @Override public E pollFirst() { throw new UnsupportedOperationException(); }
+ @Override public E pollLast() { throw new UnsupportedOperationException(); }
+ @Override
+ public NavigableSet descendingSet() {
+ return new UnmodifiableNavigableSet<>(ns.descendingSet());
+ }
+
+ @Override
+ public Iterator descendingIterator() {
+ return descendingSet().iterator();
+ }
+
+ @Override
+ public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return new UnmodifiableNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
+ }
+
+ @Override
+ public NavigableSet headSet(E toElement, boolean inclusive) {
+ return new UnmodifiableNavigableSet<>(ns.headSet(toElement, inclusive));
+ }
+
+ @Override
+ public NavigableSet tailSet(E fromElement, boolean inclusive) {
+ return new UnmodifiableNavigableSet<>(ns.tailSet(fromElement, inclusive));
+ }
+ }
+
+ /**
* Returns an unmodifiable view of the specified list. This method allows
* modules to provide users with "read-only" access to internal
* lists. Query operations on the returned list "read through" to the
@@ -1238,6 +1305,7 @@
static class UnmodifiableList extends UnmodifiableCollection
implements List {
private static final long serialVersionUID = -283967356065247728L;
+
final List extends E> list;
UnmodifiableList(List extends E> list) {
@@ -1670,6 +1738,131 @@
public K lastKey() {return sm.lastKey();}
}
+ /**
+ * Returns an unmodifiable view of the specified navigable map. This method
+ * allows modules to provide users with "read-only" access to internal
+ * navigable maps. Query operations on the returned navigable map "read
+ * through" to the specified navigable map. Attempts to modify the returned
+ * navigable map, whether direct, via its collection views, or via its
+ * subMap, headMap, or tailMap views, result in
+ * an UnsupportedOperationException.
+ *
+ * The returned navigable map will be serializable if the specified
+ * navigable map is serializable.
+ *
+ * @param m the navigable map for which an unmodifiable view is to be
+ * returned
+ * @return an unmodifiable view of the specified navigable map
+ * @since 1.8
+ */
+ public static NavigableMap unmodifiableNavigableMap(NavigableMap m) {
+ return new UnmodifiableNavigableMap<>(m);
+ }
+
+ /**
+ * @serial include
+ */
+ static class UnmodifiableNavigableMap
+ extends UnmodifiableSortedMap
+ implements NavigableMap, Serializable {
+ private static final long serialVersionUID = -4858195264774772197L;
+
+ private final NavigableMap nm;
+
+ UnmodifiableNavigableMap(NavigableMap m) {super(m); nm = m;}
+
+ @Override
+ public Entry lowerEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.lowerEntry(key));
+ }
+
+ @Override
+ public K lowerKey(K key) {
+ return nm.lowerKey(key);
+ }
+
+ @Override
+ public Entry floorEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.floorEntry(key));
+ }
+
+ @Override
+ public K floorKey(K key) {
+ return nm.floorKey(key);
+ }
+
+ @Override
+ public Entry ceilingEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.ceilingEntry(key));
+ }
+
+ @Override
+ public K ceilingKey(K key) {
+ return nm.ceilingKey(key);
+ }
+
+ @Override
+ public Entry higherEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.higherEntry(key));
+ }
+
+ @Override
+ public K higherKey(K key) {
+ return nm.higherKey(key);
+ }
+
+ @Override
+ public Entry firstEntry() {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.firstEntry());
+ }
+
+ @Override
+ public Entry lastEntry() {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.lastEntry());
+ }
+
+ @Override
+ public Entry pollFirstEntry() {
+ Entry entry = (Entry) nm.pollFirstEntry();
+ return (null == entry) ? null : new UnmodifiableEntrySet.UnmodifiableEntry(entry);
+ }
+
+ @Override
+ public Entry pollLastEntry() {
+ Entry entry = (Entry) nm.pollLastEntry();
+ return (null == entry) ? null : new UnmodifiableEntrySet.UnmodifiableEntry(entry);
+ }
+
+ @Override
+ public NavigableMap descendingMap() {
+ return unmodifiableNavigableMap(nm.descendingMap());
+ }
+
+ @Override
+ public NavigableSet navigableKeySet() {
+ return unmodifiableNavigableSet(nm.navigableKeySet());
+ }
+
+ @Override
+ public NavigableSet descendingKeySet() {
+ return unmodifiableNavigableSet(nm.descendingKeySet());
+ }
+
+ @Override
+ public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return unmodifiableNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive));
+ }
+
+ @Override
+ public NavigableMap headMap(K toKey, boolean inclusive) {
+ return unmodifiableNavigableMap(nm.headMap(toKey, inclusive));
+ }
+
+ @Override
+ public NavigableMap tailMap(K fromKey, boolean inclusive) {
+ return unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive));
+ }
+ }
// Synch Wrappers
@@ -1723,14 +1916,13 @@
final Object mutex; // Object on which to synchronize
SynchronizedCollection(Collection c) {
- if (c==null)
- throw new NullPointerException();
- this.c = c;
+ this.c = Objects.requireNonNull(c);
mutex = this;
}
+
SynchronizedCollection(Collection c, Object mutex) {
- this.c = c;
- this.mutex = mutex;
+ this.c = Objects.requireNonNull(c);
+ this.mutex = Objects.requireNonNull(mutex);
}
public int size() {
@@ -1945,6 +2137,104 @@
}
/**
+ * Returns a synchronized (thread-safe) sorted set backed by the specified
+ * navigable set. In order to guarantee serial access, it is critical that
+ * all access to the backing sorted set is accomplished
+ * through the returned navigable set (or its views).
+ *
+ * It is imperative that the user manually synchronize on the returned
+ * navigable set when iterating over it or any of its {@code subSet},
+ * {@code headSet}, or {@code tailSet} views.
+ *
+ * SortedSet s = Collections.synchronizedNavigableSet(new TreeSet());
+ * ...
+ * synchronized (s) {
+ * Iterator i = s.iterator(); // Must be in the synchronized block
+ * while (i.hasNext())
+ * foo(i.next());
+ * }
+ *
+ * or:
+ *
+ * SortedSet s = Collections.synchronizedNavigableSet(new TreeSet());
+ * SortedSet s2 = s.headSet(foo);
+ * ...
+ * synchronized (s) { // Note: s, not s2!!!
+ * Iterator i = s2.iterator(); // Must be in the synchronized block
+ * while (i.hasNext())
+ * foo(i.next());
+ * }
+ *
+ * Failure to follow this advice may result in non-deterministic behavior.
+ *
+ * The returned navigable set will be serializable if the specified
+ * navigable set is serializable.
+ *
+ * @param s the navigable set to be "wrapped" in a synchronized navigable
+ * set
+ * @return a synchronized view of the specified navigable set
+ * @since 1.8
+ */
+ public static NavigableSet synchronizedNavigableSet(NavigableSet s) {
+ return new SynchronizedNavigableSet<>(s);
+ }
+
+ /**
+ * @serial include
+ */
+ static class SynchronizedNavigableSet
+ extends SynchronizedSortedSet
+ implements NavigableSet
+ {
+ private static final long serialVersionUID = -5505529816273629798L;
+
+ private final NavigableSet ns;
+
+ SynchronizedNavigableSet(NavigableSet s) {
+ super(s);
+ ns = s;
+ }
+
+ SynchronizedNavigableSet(NavigableSet s, Object mutex) {
+ super(s, mutex);
+ ns = s;
+ }
+ public E lower(E e) { synchronized (mutex) {return ns.lower(e);} }
+ public E floor(E e) { synchronized (mutex) {return ns.floor(e);} }
+ public E ceiling(E e) { synchronized (mutex) {return ns.ceiling(e);} }
+ public E higher(E e) { synchronized (mutex) {return ns.higher(e);} }
+ public E pollFirst() { synchronized (mutex) {return ns.pollFirst();} }
+ public E pollLast() { synchronized (mutex) {return ns.pollLast();} }
+
+ public NavigableSet descendingSet() {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex);
+ }
+ }
+
+ public Iterator descendingIterator()
+ { synchronized (mutex) { return descendingSet().iterator(); } }
+
+ public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex);
+ }
+ }
+
+ public NavigableSet headSet(E toElement, boolean inclusive) {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex);
+ }
+ }
+
+ public NavigableSet tailSet(E fromElement, boolean inclusive) {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, inclusive));
+ }
+ }
+ }
+
+ /**
* Returns a synchronized (thread-safe) list backed by the specified
* list. In order to guarantee serial access, it is critical that
* all access to the backing list is accomplished
@@ -2153,9 +2443,7 @@
final Object mutex; // Object on which to synchronize
SynchronizedMap(Map m) {
- if (m==null)
- throw new NullPointerException();
- this.m = m;
+ this.m = Objects.requireNonNull(m);
mutex = this;
}
@@ -2334,7 +2622,6 @@
return new SynchronizedSortedMap<>(m);
}
-
/**
* @serial include
*/
@@ -2384,6 +2671,170 @@
}
}
+ /**
+ * Returns a synchronized (thread-safe) navigable map backed by the
+ * specified navigable map. In order to guarantee serial access, it is
+ * critical that all access to the backing navigable map is
+ * accomplished through the returned navigable map (or its views).
+ *
+ * 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 subMap}, {@code headMap} or
+ * {@code tailMap} views.
+ *
+ * SortedMap m = Collections.synchronizedNavigableMap(new TreeMap());
+ * ...
+ * Set s = m.keySet(); // Needn't be in synchronized block
+ * ...
+ * synchronized (m) { // Synchronizing on m, not s!
+ * Iterator i = s.iterator(); // Must be in synchronized block
+ * while (i.hasNext())
+ * foo(i.next());
+ * }
+ *
+ * or:
+ *
+ * SortedMap m = Collections.synchronizedNavigableMap(new TreeMap());
+ * SortedMap m2 = m.subMap(foo, bar);
+ * ...
+ * Set s2 = m2.keySet(); // Needn't be in synchronized block
+ * ...
+ * synchronized (m) { // Synchronizing on m, not m2 or s2!
+ * Iterator i = s.iterator(); // Must be in synchronized block
+ * while (i.hasNext())
+ * foo(i.next());
+ * }
+ *
+ * Failure to follow this advice may result in non-deterministic behavior.
+ *
+ * The returned navigable map will be serializable if the specified
+ * navigable map is serializable.
+ *
+ * @param m the navigable map to be "wrapped" in a synchronized navigable
+ * map
+ * @return a synchronized view of the specified navigable map.
+ * @since 1.8
+ */
+ public static NavigableMap synchronizedNavigableMap(NavigableMap m) {
+ return new SynchronizedNavigableMap<>(m);
+ }
+
+ /**
+ * A synchronized NavigableMap.
+ *
+ * @serial include
+ */
+ static class SynchronizedNavigableMap
+ extends SynchronizedSortedMap
+ implements NavigableMap
+ {
+ private static final long serialVersionUID = 699392247599746807L;
+
+ private final NavigableMap nm;
+
+ SynchronizedNavigableMap(NavigableMap m) {
+ super(m);
+ nm = m;
+ }
+ SynchronizedNavigableMap(NavigableMap m, Object mutex) {
+ super(m, mutex);
+ nm = m;
+ }
+
+ public Entry lowerEntry(K key)
+ { synchronized (mutex) { return nm.lowerEntry(key); } }
+ public K lowerKey(K key)
+ { synchronized (mutex) { return nm.lowerKey(key); } }
+ public Entry floorEntry(K key)
+ { synchronized (mutex) { return nm.floorEntry(key); } }
+ public K floorKey(K key)
+ { synchronized (mutex) { return nm.floorKey(key); } }
+ public Entry ceilingEntry(K key)
+ { synchronized (mutex) { return nm.ceilingEntry(key); } }
+ public K ceilingKey(K key)
+ { synchronized (mutex) { return nm.ceilingKey(key); } }
+
+ @Override
+ public Entry higherEntry(K key) {
+ synchronized (mutex) { return nm.higherEntry(key); }
+ }
+
+ @Override
+ public K higherKey(K key) {
+ synchronized (mutex) { return nm.higherKey(key); }
+ }
+
+ @Override
+ public Entry firstEntry() {
+ synchronized (mutex) { return nm.firstEntry(); }
+ }
+
+ @Override
+ public Entry lastEntry() {
+ synchronized (mutex) { return nm.lastEntry(); }
+ }
+
+ @Override
+ public Entry pollFirstEntry() {
+ synchronized (mutex) {
+ return nm.pollFirstEntry();
+ }
+ }
+
+ @Override
+ public Entry pollLastEntry() {
+ synchronized (mutex) {
+ return nm.pollLastEntry();
+ }
+ }
+
+ @Override
+ public NavigableMap descendingMap() {
+ synchronized (mutex) {
+ return (NavigableMap)
+ new SynchronizedNavigableMap(nm.descendingMap(), mutex);
+ }
+ }
+
+ @Override
+ public NavigableSet navigableKeySet() {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet(nm.navigableKeySet(), mutex);
+ }
+ }
+
+ @Override
+ public NavigableSet descendingKeySet() {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet(nm.descendingKeySet(), mutex);
+ }
+ }
+
+ @Override
+ public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ synchronized (mutex) {
+ return (NavigableMap) new SynchronizedNavigableMap(
+ nm.subMap(fromKey, fromInclusive, toKey, toInclusive), mutex);
+ }
+ }
+
+ @Override
+ public NavigableMap headMap(K toKey, boolean inclusive) {
+ synchronized (mutex) {
+ return (NavigableMap) new SynchronizedNavigableMap(
+ nm.headMap(toKey, inclusive), mutex);
+ }
+ }
+
+ @Override
+ public NavigableMap tailMap(K fromKey, boolean inclusive) {
+ synchronized (mutex) {
+ return (NavigableMap) new SynchronizedNavigableMap(
+ nm.tailMap(fromKey, inclusive), mutex);
+ }
+ }
+ }
+
// Dynamically typesafe collection wrappers
/**
@@ -2415,12 +2866,12 @@
* program to wrap the collection with a dynamically typesafe view.
* For example, this declaration:
* {@code
- * Collection c = new HashSet();
+ * Collection c = new HashSet<>();
* }
* may be replaced temporarily by this one:
* {@code
* Collection c = Collections.checkedCollection(
- * new HashSet(), String.class);
+ * new HashSet<>(), String.class);
* }
* Running the program again will cause it to fail at the point where
* an incorrectly typed element is inserted into the collection, clearly
@@ -2706,6 +3157,7 @@
implements SortedSet, Serializable
{
private static final long serialVersionUID = 1599911165492914959L;
+
private final SortedSet ss;
CheckedSortedSet(SortedSet s, Class type) {
@@ -2728,6 +3180,77 @@
}
}
+/**
+ * Returns a dynamically typesafe view of the specified navigable set.
+ * Any attempt to insert an element of the wrong type will result in an
+ * immediate {@link ClassCastException}. Assuming a navigable set
+ * contains no incorrectly typed elements prior to the time a
+ * dynamically typesafe view is generated, and that all subsequent
+ * access to the navigable set takes place through the view, it is
+ * guaranteed that the navigable set cannot contain an incorrectly
+ * typed element.
+ *
+ * A discussion of the use of dynamically typesafe views may be
+ * found in the documentation for the {@link #checkedCollection
+ * checkedCollection} method.
+ *
+ *
The returned navigable set will be serializable if the specified
+ * navigable set is serializable.
+ *
+ *
Since {@code null} is considered to be a value of any reference
+ * type, the returned navigable set permits insertion of null elements
+ * whenever the backing sorted set does.
+ *
+ * @param s the navigable set for which a dynamically typesafe view is to be
+ * returned
+ * @param type the type of element that {@code s} is permitted to hold
+ * @return a dynamically typesafe view of the specified navigable set
+ * @since 1.8
+ */
+ public static NavigableSet checkedNavigableSet(NavigableSet s,
+ Class type) {
+ return new CheckedNavigableSet<>(s, type);
+ }
+
+ /**
+ * @serial include
+ */
+ static class CheckedNavigableSet extends CheckedSortedSet
+ implements NavigableSet, Serializable
+ {
+ private static final long serialVersionUID = -5429120189805438922L;
+
+ private final NavigableSet ns;
+
+ CheckedNavigableSet(NavigableSet s, Class type) {
+ super(s, type);
+ ns = s;
+ }
+
+ public E lower(E e) { return ns.lower(e); }
+ public E floor(E e) { return ns.floor(e); }
+ public E ceiling(E e) { return ns.ceiling(e); }
+ public E higher(E e) { return ns.higher(e); }
+ public E pollFirst() { return ns.pollFirst(); }
+ public E pollLast() {return ns.pollLast(); }
+ public NavigableSet descendingSet()
+ { return checkedNavigableSet(ns.descendingSet(), type); }
+ public Iterator descendingIterator()
+ {return checkedNavigableSet(ns.descendingSet(), type).iterator(); }
+
+ public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type);
+ }
+
+ public NavigableSet headSet(E toElement, boolean inclusive) {
+ return checkedNavigableSet(ns.headSet(toElement, inclusive), type);
+ }
+
+ public NavigableSet tailSet(E fromElement, boolean inclusive) {
+ return checkedNavigableSet(ns.tailSet(fromElement, inclusive), type);
+ }
+ }
+
/**
* Returns a dynamically typesafe view of the specified list.
* Any attempt to insert an element of the wrong type will result in
@@ -2940,11 +3463,9 @@
}
CheckedMap(Map m, Class keyType, Class valueType) {
- if (m == null || keyType == null || valueType == null)
- throw new NullPointerException();
- this.m = m;
- this.keyType = keyType;
- this.valueType = valueType;
+ this.m = Objects.requireNonNull(m);
+ this.keyType = Objects.requireNonNull(keyType);
+ this.valueType = Objects.requireNonNull(valueType);
}
public int size() { return m.size(); }
@@ -3325,6 +3846,172 @@
}
}
+ /**
+ * Returns a dynamically typesafe view of the specified navigable map.
+ * Any attempt to insert a mapping whose key or value have the wrong
+ * type will result in an immediate {@link ClassCastException}.
+ * Similarly, any attempt to modify the value currently associated with
+ * a key will result in an immediate {@link ClassCastException},
+ * whether the modification is attempted directly through the map
+ * itself, or through a {@link Map.Entry} instance obtained from the
+ * map's {@link Map#entrySet() entry set} view.
+ *
+ * Assuming a map contains no incorrectly typed keys or values
+ * prior to the time a dynamically typesafe view is generated, and
+ * that all subsequent access to the map takes place through the view
+ * (or one of its collection views), it is guaranteed that the
+ * map cannot contain an incorrectly typed key or value.
+ *
+ *
A discussion of the use of dynamically typesafe views may be
+ * found in the documentation for the {@link #checkedCollection
+ * checkedCollection} method.
+ *
+ *
The returned map will be serializable if the specified map is
+ * serializable.
+ *
+ *
Since {@code null} is considered to be a value of any reference
+ * type, the returned map permits insertion of null keys or values
+ * whenever the backing map does.
+ *
+ * @param type of map keys
+ * @param type of map values
+ * @param m the map for which a dynamically typesafe view is to be
+ * returned
+ * @param keyType the type of key that {@code m} is permitted to hold
+ * @param valueType the type of value that {@code m} is permitted to hold
+ * @return a dynamically typesafe view of the specified map
+ * @since 1.8
+ */
+ public static NavigableMap checkedNavigableMap(NavigableMap m,
+ Class keyType,
+ Class valueType) {
+ return new CheckedNavigableMap<>(m, keyType, valueType);
+ }
+
+ /**
+ * @serial include
+ */
+ static class CheckedNavigableMap extends CheckedSortedMap
+ implements NavigableMap, Serializable
+ {
+ private static final long serialVersionUID = -4852462692372534096L;
+
+ private final NavigableMap nm;
+
+ CheckedNavigableMap(NavigableMap m,
+ Class keyType, Class valueType) {
+ super(m, keyType, valueType);
+ nm = m;
+ }
+
+ public Comparator super K> comparator() { return nm.comparator(); }
+ public K firstKey() { return nm.firstKey(); }
+ public K lastKey() { return nm.lastKey(); }
+
+ public NavigableMap subMap(K fromKey, K toKey) {
+ return checkedNavigableMap((NavigableMap)nm.subMap(fromKey, toKey),
+ keyType, valueType);
+ }
+ public NavigableMap headMap(K toKey) {
+ return checkedNavigableMap((NavigableMap)nm.headMap(toKey), keyType, valueType);
+ }
+ public NavigableMap tailMap(K fromKey) {
+ return checkedNavigableMap((NavigableMap)nm.tailMap(fromKey), keyType, valueType);
+ }
+
+ @Override
+ public Entry lowerEntry(K key) {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.lowerEntry(key), valueType);
+ }
+
+ @Override
+ public K lowerKey(K key) {
+ return nm.lowerKey(key);
+ }
+
+ @Override
+ public Entry floorEntry(K key) {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.lowerEntry(key), valueType);
+ }
+
+ @Override
+ public K floorKey(K key) {
+ return nm.floorKey(key);
+ }
+
+ @Override
+ public Entry ceilingEntry(K key) {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.ceilingEntry(key), valueType);
+ }
+
+ @Override
+ public K ceilingKey(K key) {
+ return nm.ceilingKey(key);
+ }
+
+ @Override
+ public Entry higherEntry(K key) {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.higherEntry(key), valueType);
+ }
+
+ @Override
+ public K higherKey(K key) {
+ return nm.higherKey(key);
+ }
+
+ @Override
+ public Entry firstEntry() {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.firstEntry(), valueType);
+ }
+
+ @Override
+ public Entry lastEntry() {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.lastEntry(), valueType);
+ }
+
+ @Override
+ public Entry pollFirstEntry() {
+ Entry entry = nm.pollFirstEntry();
+ return (null == entry) ? null : new CheckedMap.CheckedEntrySet.CheckedEntry(entry, valueType);
+ }
+
+ @Override
+ public Entry pollLastEntry() {
+ Entry entry = nm.pollLastEntry();
+ return (null == entry) ? null : new CheckedMap.CheckedEntrySet.CheckedEntry(entry, valueType);
+ }
+
+ @Override
+ public NavigableMap descendingMap() {
+ return checkedNavigableMap(nm.descendingMap(), keyType, valueType);
+ }
+
+ @Override
+ public NavigableSet navigableKeySet() {
+ return checkedNavigableSet(nm.navigableKeySet(), keyType);
+ }
+
+ @Override
+ public NavigableSet descendingKeySet() {
+ return checkedNavigableSet(nm.descendingKeySet(), keyType);
+ }
+
+ @Override
+ public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return checkedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), keyType, valueType);
+ }
+
+ @Override
+ public NavigableMap headMap(K toKey, boolean inclusive) {
+ return checkedNavigableMap(nm.headMap(toKey, inclusive), keyType, valueType);
+ }
+
+ @Override
+ public NavigableMap tailMap(K fromKey, boolean inclusive) {
+ return checkedNavigableMap(nm.tailMap(fromKey, inclusive), keyType, valueType);
+ }
+ }
+
// Empty collections
/**
@@ -3467,11 +4154,12 @@
*
* Set<String> s = Collections.emptySet();
*
- * Implementation note: Implementations of this method need not
- * create a separate Set object for each call. Using this
- * method is likely to have comparable cost to using the like-named
- * field. (Unlike this method, the field does not provide type safety.)
- *
+ * @implNote Implementations of this method need not create a separate
+ * {@code Set} object for each call. Using this method is likely to have
+ * comparable cost to using the like-named field. (Unlike this method, the
+ * field does not provide type safety.)
+ *
+ * @return the empty set
* @see #EMPTY_SET
* @since 1.5
*/
@@ -3525,121 +4213,45 @@
}
/**
- * Returns the empty sorted set (immutable). This set is serializable.
- *
- * This example illustrates the type-safe way to obtain an empty sorted
- * set:
- *
- * SortedSet<String> s = Collections.emptySortedSet();
- *
- * Implementation note: Implementations of this method need not
- * create a separate SortedSet object for each call.
- *
+ * Returns an empty sorted set (immutable). This set is serializable.
+ *
+ * This example illustrates the type-safe way to obtain an empty
+ * sorted set:
+ *
{@code
+ * SortedSet s = Collections.emptySortedSet();
+ * }
+ *
+ * @implNote Implementations of this method need not create a separate
+ * {@code SortedSet} object for each call.
+ *
+ * @param type of elements, if there were any, in the set
+ * @return the empty sorted set
* @since 1.8
*/
@SuppressWarnings("unchecked")
- public static final SortedSet emptySortedSet() {
- return (SortedSet) new EmptySortedSet<>();
+ public static SortedSet emptySortedSet() {
+ return (SortedSet) EmptyNavigableSet.EMPTY_NAVIGABLE_SET;
}
/**
- * @serial include
+ * Returns an empty navigable set (immutable). This set is serializable.
+ *
+ * This example illustrates the type-safe way to obtain an empty
+ * navigable set:
+ *
{@code
+ * NavigableSet s = Collections.emptyNavigableSet();
+ * }
+ *
+ * @implNote Implementations of this method need not
+ * create a separate {@code NavigableSet} object for each call.
+ *
+ * @param type of elements, if there were any, in the set
+ * @return the empty navigable set
+ * @since 1.8
*/
- private static class EmptySortedSet
- extends AbstractSet
- implements SortedSet, Serializable
- {
- private static final long serialVersionUID = 6316515401502265487L;
- public Iterator iterator() { return emptyIterator(); }
- public int size() {return 0;}
- public boolean isEmpty() {return true;}
- public boolean contains(Object obj) {return false;}
- public boolean containsAll(Collection> c) { return c.isEmpty(); }
- public Object[] toArray() { return new Object[0]; }
-
- public E[] toArray(E[] a) {
- if (a.length > 0)
- a[0] = null;
- return a;
- }
-
- // Preserves singleton property
- private Object readResolve() {
- return new EmptySortedSet<>();
- }
-
- @Override
- public Comparator super E> comparator() {
- return null;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public SortedSet subSet(Object fromElement, Object toElement) {
- Objects.requireNonNull(fromElement);
- Objects.requireNonNull(toElement);
-
- if (!(fromElement instanceof Comparable) ||
- !(toElement instanceof Comparable))
- {
- throw new ClassCastException();
- }
-
- if ((((Comparable)fromElement).compareTo(toElement) >= 0) ||
- (((Comparable)toElement).compareTo(fromElement) < 0))
- {
- throw new IllegalArgumentException();
- }
-
- return emptySortedSet();
- }
-
- @Override
- public SortedSet headSet(Object toElement) {
- Objects.requireNonNull(toElement);
-
- if (!(toElement instanceof Comparable)) {
- throw new ClassCastException();
- }
-
- return emptySortedSet();
- }
-
- @Override
- public SortedSet tailSet(Object fromElement) {
- Objects.requireNonNull(fromElement);
-
- if (!(fromElement instanceof Comparable)) {
- throw new ClassCastException();
- }
-
- return emptySortedSet();
- }
-
- @Override
- public E first() {
- throw new NoSuchElementException();
- }
-
- @Override
- public E last() {
- throw new NoSuchElementException();
- }
-
- // Override default methods in Collection
- @Override
- public void forEach(Consumer super E> action) {
- Objects.requireNonNull(action);
- }
-
- @Override
- public boolean removeIf(Predicate super E> filter) {
- Objects.requireNonNull(filter);
- return false;
- }
-
- @Override
- public Spliterator spliterator() { return Spliterators.emptySpliterator(); }
+ @SuppressWarnings("unchecked")
+ public static NavigableSet emptyNavigableSet() {
+ return (NavigableSet) EmptyNavigableSet.EMPTY_NAVIGABLE_SET;
}
/**
@@ -3739,6 +4351,299 @@
}
/**
+ * An empty navigable map with enforced bounds upon the key set. The bounds
+ * are generated via the various sub-map operations and enforced on
+ * subsequent sub-map operations.
+ *
+ * @serial include
+ *
+ * @param type of keys, if there were any, and bounds
+ * @param type of values, if there were any
+ */
+ private static class BoundedEmptyNavigableMap extends EmptyNavigableMap
+ implements Serializable {
+
+ private static final long serialVersionUID = 5065418537829651507L;
+
+ /**
+ * Our bounded keyset.
+ */
+ final BoundedEmptyNavigableSet keySet;
+
+ private BoundedEmptyNavigableMap(BoundedEmptyNavigableSet keySet) {
+ this.keySet = Objects.requireNonNull(keySet);
+ }
+
+ public Comparator super K> comparator()
+ { return keySet.comparator(); }
+
+ @Override
+ public NavigableMap descendingMap() {
+ NavigableSet descending = keySet.descendingSet();
+
+ if(descending == Collections.emptyNavigableSet()) {
+ return Collections.emptyNavigableMap();
+ } else {
+ return new BoundedEmptyNavigableMap((BoundedEmptyNavigableSet) descending);
+ }
+ }
+
+ public BoundedEmptyNavigableSet navigableKeySet() { return keySet; }
+ public EmptyNavigableSet descendingKeySet()
+ { return keySet.descendingSet(); }
+
+ @Override
+ public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return new BoundedEmptyNavigableMap(keySet.subSet(
+ fromKey, fromInclusive,
+ toKey, toInclusive));
+ }
+
+ @Override
+ public NavigableMap headMap(K toKey, boolean inclusive) {
+ return new BoundedEmptyNavigableMap(
+ keySet.headSet(toKey, inclusive));
+ }
+
+ @Override
+ public NavigableMap tailMap(K fromKey, boolean inclusive) {
+ return new BoundedEmptyNavigableMap(
+ keySet.tailSet(fromKey, inclusive));
+ }
+ }
+
+ /**
+ * @serial include
+ *
+ * @param type of elements, if there were any
+ */
+ private static class EmptyNavigableSet extends EmptySet
+ implements NavigableSet, Serializable {
+ private static final long serialVersionUID = -6291252904449939134L;
+
+ @SuppressWarnings("rawtypes")
+ private static final NavigableSet EMPTY_NAVIGABLE_SET =
+ new EmptyNavigableSet();
+
+ EmptyNavigableSet() { }
+
+ @Override
+ public boolean contains(Object obj) {
+ Comparable e = (Comparable) Objects.requireNonNull(obj);
+ return obj != e;
+ }
+
+ // Preserves singleton property
+ private Object readResolve()
+ { return Collections.emptyNavigableSet(); }
+ public E lower(E e) { return null; }
+ public E floor(E e) { return null; }
+ public E ceiling(E e) { return null; }
+ public E higher(E e) { return null; }
+ public E pollFirst() { throw new UnsupportedOperationException(); }
+ public E pollLast() { throw new UnsupportedOperationException(); }
+
+ public EmptyNavigableSet descendingSet() {
+ return new BoundedEmptyNavigableSet(null, false, null, false, true);
+ }
+
+ public Iterator descendingIterator()
+ { return Collections.emptyIterator(); }
+
+ public BoundedEmptyNavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return new BoundedEmptyNavigableSet<>(
+ (Comparable) Objects.requireNonNull(fromElement), fromInclusive,
+ (Comparable) Objects.requireNonNull(toElement), toInclusive,
+ false);
+ }
+
+ public BoundedEmptyNavigableSet headSet(E toElement, boolean inclusive) {
+ return new BoundedEmptyNavigableSet<>(
+ null, false,
+ (Comparable) Objects.requireNonNull(toElement), inclusive,
+ false);
+ }
+
+ public BoundedEmptyNavigableSet tailSet(E fromElement, boolean inclusive) {
+ return new BoundedEmptyNavigableSet<>(
+ (Comparable) Objects.requireNonNull(fromElement), inclusive,
+ null, false,
+ false);
+ }
+
+ public final SortedSet subSet(E fromElement, E toElement)
+ { return subSet(fromElement, true, toElement, false); }
+ public final SortedSet headSet(E toElement)
+ { return headSet(toElement, true); }
+ public final SortedSet tailSet(E fromElement)
+ { return tailSet(fromElement, false); }
+
+ public Comparator super E> comparator() { return null; }
+ public E first() { throw new NoSuchElementException(); }
+ public E last() { throw new NoSuchElementException(); }
+ }
+
+ /**
+ * An empty NavigableSet but bounds are maintained. If you try to sub-set
+ * outside the bounds you will get an IllegalArgumentException.
+ *
+ * @serial include
+ *
+ * @param type of elements, if there were any, and bounds
+ */
+ private static class BoundedEmptyNavigableSet extends EmptyNavigableSet
+ implements Serializable {
+ private static final long serialVersionUID = 3393358742248855583L;
+
+ /**
+ * {@code true} if lowerBound is "greater" than upperBound.
+ */
+ final boolean descending;
+ /**
+ * {@code true} if lowerBound is inclusive.
+ */
+ final boolean lowerInclusive;
+ /**
+ * {@code true} if upperBound is inclusive.
+ */
+ final boolean upperInclusive;
+ /**
+ * The lower bound of the set.
+ */
+ final Comparable lowerBound;
+ /**
+ * The upper bound of the set.
+ */
+ final Comparable upperBound;
+
+ public BoundedEmptyNavigableSet(
+ Comparable fromElement, boolean lowerInclusive,
+ Comparable toElement, boolean upperInclusive,
+ boolean descending) {
+ this.descending = descending;
+
+ if ((fromElement != null) && (toElement != null)) {
+ // both bounds are present we need to ensure that they make
+ // sense.
+ int fromCompared = Integer.signum(fromElement.compareTo((E)toElement));
+ int toCompared = Integer.signum(toElement.compareTo((E)fromElement));
+
+ if(fromCompared != -toCompared) {
+ throw new IllegalArgumentException("inconsistent compareTo");
+ }
+
+ if (descending) {
+ if (fromCompared < 0) {
+ throw new IllegalArgumentException();
+ }
+ } else {
+ if (fromCompared > 0) {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
+ this.lowerBound = fromElement;
+ this.lowerInclusive = lowerInclusive;
+ this.upperBound = toElement;
+ this.upperInclusive = upperInclusive;
+ }
+
+ @Override
+ public Comparator super E> comparator()
+ { return descending ? Collections.reverseOrder() : null; }
+
+ private Comparable inBounds(E element) {
+ if (!descending) {
+ if (null != lowerBound) {
+ if (lowerInclusive) {
+ if (lowerBound.compareTo(element) > 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ } else {
+ if (lowerBound.compareTo(element) >= 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ }
+ }
+
+ if (null != upperBound) {
+ if (upperInclusive) {
+ if (upperBound.compareTo(element) < 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ } else {
+ if (upperBound.compareTo(element) <= 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ }
+ }
+ } else {
+ if (null != lowerBound) {
+ if (lowerInclusive) {
+ if (lowerBound.compareTo(element) < 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ } else {
+ if (lowerBound.compareTo(element) <= 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ }
+ }
+
+ if (null != upperBound) {
+ if (upperInclusive) {
+ if (upperBound.compareTo(element) > 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ } else {
+ if (upperBound.compareTo(element) >= 0) {
+ throw new IllegalArgumentException("out of bounds");
+ }
+ }
+ }
+ }
+
+ return (Comparable) Objects.requireNonNull(element);
+ }
+
+ @Override
+ public EmptyNavigableSet descendingSet() {
+ if (upperBound == null && lowerBound == null && descending) {
+ return (EmptyNavigableSet) Collections.emptyNavigableSet();
+ }
+ return new BoundedEmptyNavigableSet(
+ upperBound, upperInclusive,
+ lowerBound, lowerInclusive,
+ !descending);
+ }
+
+ @Override
+ public BoundedEmptyNavigableSet subSet(E fromKey, boolean fromInclusive, E toKey, boolean toInclusive) {
+ return new BoundedEmptyNavigableSet(
+ inBounds(fromKey), fromInclusive,
+ inBounds(toKey), toInclusive,
+ descending);
+ }
+
+ @Override
+ public BoundedEmptyNavigableSet headSet(E toKey, boolean inclusive) {
+ return new BoundedEmptyNavigableSet(
+ lowerBound, lowerInclusive,
+ inBounds(Objects.requireNonNull(toKey)), inclusive,
+ descending);
+ }
+
+ @Override
+ public BoundedEmptyNavigableSet tailSet(E fromKey, boolean inclusive) {
+ return new BoundedEmptyNavigableSet(
+ inBounds(Objects.requireNonNull(fromKey)), inclusive,
+ upperBound, upperInclusive,
+ descending);
+ }
+ }
+
+ /**
* The empty map (immutable). This map is serializable.
*
* @see #emptyMap()
@@ -3750,15 +4655,16 @@
/**
* Returns the empty map (immutable). This map is serializable.
*
- * This example illustrates the type-safe way to obtain an empty set:
+ *
This example illustrates the type-safe way to obtain an empty map:
*
* Map<String, Date> s = Collections.emptyMap();
*
- * Implementation note: Implementations of this method need not
- * create a separate Map object for each call. Using this
- * method is likely to have comparable cost to using the like-named
- * field. (Unlike this method, the field does not provide type safety.)
- *
+ * @implNote Implementations of this method need not create a separate
+ * {@code Map} object for each call. Using this method is likely to have
+ * comparable cost to using the like-named field. (Unlike this method, the
+ * field does not provide type safety.)
+ *
+ * @return an empty map
* @see #EMPTY_MAP
* @since 1.5
*/
@@ -3768,6 +4674,44 @@
}
/**
+ * Returns an empty sorted map (immutable). This map is serializable.
+ *
+ * This example illustrates the type-safe way to obtain an empty map:
+ *
{@code
+ * SortedMap s = Collections.emptySortedMap();
+ * }
+ *
+ * @implNote Implementations of this method need not create a separate
+ * {@code SortedMap} object for each call.
+ *
+ * @return an empty sorted map
+ * @since 1.8
+ */
+ @SuppressWarnings("unchecked")
+ public static final SortedMap emptySortedMap() {
+ return (SortedMap) EmptyNavigableMap.EMPTY_NAVIGABLE_MAP;
+ }
+
+ /**
+ * Returns an empty navigable map (immutable). This map is serializable.
+ *
+ * This example illustrates the type-safe way to obtain an empty map:
+ *
{@code
+ * NavigableMap s = Collections.emptyNavigableMap();
+ * }
+ *
+ * @implNote Implementations of this method need not create a separate
+ * {@code NavigableMap} object for each call.
+ *
+ * @return an empty navigable map
+ * @since 1.8
+ */
+ @SuppressWarnings("unchecked")
+ public static final NavigableMap emptyNavigableMap() {
+ return (NavigableMap) EmptyNavigableMap.EMPTY_NAVIGABLE_MAP;
+ }
+
+ /**
* @serial include
*/
private static class EmptyMap
@@ -3858,6 +4802,129 @@
}
}
+ /**
+ * An empty navigable map.
+ *
+ * @param type of keys, if there were any in this map
+ * @param type of values, if there were any in this map
+ *
+ * @serial include
+ */
+ private static class EmptyNavigableMap extends EmptyMap
+ implements NavigableMap, Serializable {
+ private static final long serialVersionUID = -2239321462712562324L;
+
+ @SuppressWarnings("rawtypes")
+ private static final NavigableMap EMPTY_NAVIGABLE_MAP =
+ new EmptyNavigableMap();
+
+ EmptyNavigableMap() {}
+
+ @Override
+ public boolean containsKey(Object obj) {
+ Comparable e = (Comparable) Objects.requireNonNull(obj);
+ return obj != e;
+ }
+
+ // Preserves singleton property
+ private Object readResolve() { return Collections.emptyNavigableMap();}
+
+ public final K firstKey() { throw new NoSuchElementException(); }
+ public final K lastKey() { throw new NoSuchElementException(); }
+
+ public Entry lowerEntry(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public K lowerKey(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public Entry floorEntry(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public K floorKey(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public Entry ceilingEntry(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public K ceilingKey(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public Entry higherEntry(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public K higherKey(K key) {
+ Comparable k = (Comparable) Objects.requireNonNull(key);
+ return null;
+ }
+
+ public Entry firstEntry() { return null; }
+ public Entry lastEntry() { return null; }
+ public Entry pollFirstEntry()
+ { throw new UnsupportedOperationException(); }
+ public Entry pollLastEntry()
+ { throw new UnsupportedOperationException(); }
+ public NavigableMap descendingMap() {
+ EmptyNavigableSet descendingKeys = descendingKeySet();
+
+ if(descendingKeys == emptyNavigableSet()) {
+ return emptyNavigableMap();
+ } else {
+ return new BoundedEmptyNavigableMap<>((BoundedEmptyNavigableSet