--- old/src/share/classes/java/util/Collections.java 2013-06-07 09:53:18.618587665 -0700 +++ new/src/share/classes/java/util/Collections.java 2013-06-07 09:53:18.406587655 -0700 @@ -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 list; UnmodifiableList(List 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 @@ -1945,6 +2138,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 +2444,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; } @@ -2384,77 +2673,238 @@ } } - // Dynamically typesafe collection wrappers - /** - * Returns a dynamically typesafe view of the specified collection. - * Any attempt to insert an element of the wrong type will result in an - * immediate {@link ClassCastException}. Assuming a collection - * contains no incorrectly typed elements prior to the time a - * dynamically typesafe view is generated, and that all subsequent - * access to the collection takes place through the view, it is - * guaranteed that the collection cannot contain an incorrectly - * typed element. - * - *

The generics mechanism in the language provides compile-time - * (static) type checking, but it is possible to defeat this mechanism - * with unchecked casts. Usually this is not a problem, as the compiler - * issues warnings on all such unchecked operations. There are, however, - * times when static type checking alone is not sufficient. For example, - * suppose a collection is passed to a third-party library and it is - * imperative that the library code not corrupt the collection by - * inserting an element of the wrong type. - * - *

Another use of dynamically typesafe views is debugging. Suppose a - * program fails with a {@code ClassCastException}, indicating that an - * incorrectly typed element was put into a parameterized collection. - * Unfortunately, the exception can occur at any time after the erroneous - * element is inserted, so it typically provides little or no information - * as to the real source of the problem. If the problem is reproducible, - * one can quickly determine its source by temporarily modifying the - * program to wrap the collection with a dynamically typesafe view. - * For example, this declaration: - *

 {@code
-     *     Collection c = new HashSet();
-     * }
- * may be replaced temporarily by this one: - *
 {@code
-     *     Collection c = Collections.checkedCollection(
-     *         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 - * identifying the source of the problem. Once the problem is fixed, the - * modified declaration may be reverted back to the original. - * - *

The returned collection does not pass the hashCode and equals - * operations through to the backing collection, but relies on - * {@code Object}'s {@code equals} and {@code hashCode} methods. This - * is necessary to preserve the contracts of these operations in the case - * that the backing collection is a set or a list. + * 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).

* - *

The returned collection will be serializable if the specified - * collection is serializable. + * 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. * - *

Since {@code null} is considered to be a value of any reference - * type, the returned collection permits insertion of null elements - * whenever the backing collection does. + *

The returned navigable map will be serializable if the specified + * navigable map is serializable. * - * @param c the collection for which a dynamically typesafe view is to be - * returned - * @param type the type of element that {@code c} is permitted to hold - * @return a dynamically typesafe view of the specified collection - * @since 1.5 + * @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 Collection checkedCollection(Collection c, - Class type) { - return new CheckedCollection<>(c, type); + public static NavigableMap synchronizedNavigableMap(NavigableMap m) { + return new SynchronizedNavigableMap<>(m); } - @SuppressWarnings("unchecked") - static T[] zeroLengthArray(Class type) { - return (T[]) Array.newInstance(type, 0); - } + + /** + * 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 + + /** + * Returns a dynamically typesafe view of the specified collection. + * Any attempt to insert an element of the wrong type will result in an + * immediate {@link ClassCastException}. Assuming a collection + * contains no incorrectly typed elements prior to the time a + * dynamically typesafe view is generated, and that all subsequent + * access to the collection takes place through the view, it is + * guaranteed that the collection cannot contain an incorrectly + * typed element. + * + *

The generics mechanism in the language provides compile-time + * (static) type checking, but it is possible to defeat this mechanism + * with unchecked casts. Usually this is not a problem, as the compiler + * issues warnings on all such unchecked operations. There are, however, + * times when static type checking alone is not sufficient. For example, + * suppose a collection is passed to a third-party library and it is + * imperative that the library code not corrupt the collection by + * inserting an element of the wrong type. + * + *

Another use of dynamically typesafe views is debugging. Suppose a + * program fails with a {@code ClassCastException}, indicating that an + * incorrectly typed element was put into a parameterized collection. + * Unfortunately, the exception can occur at any time after the erroneous + * element is inserted, so it typically provides little or no information + * as to the real source of the problem. If the problem is reproducible, + * one can quickly determine its source by temporarily modifying the + * program to wrap the collection with a dynamically typesafe view. + * For example, this declaration: + *

 {@code
+     *     Collection c = new HashSet<>();
+     * }
+ * may be replaced temporarily by this one: + *
 {@code
+     *     Collection c = Collections.checkedCollection(
+     *         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 + * identifying the source of the problem. Once the problem is fixed, the + * modified declaration may be reverted back to the original. + * + *

The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * {@code Object}'s {@code equals} and {@code hashCode} methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list. + * + *

The returned collection will be serializable if the specified + * collection is serializable. + * + *

Since {@code null} is considered to be a value of any reference + * type, the returned collection permits insertion of null elements + * whenever the backing collection does. + * + * @param c the collection for which a dynamically typesafe view is to be + * returned + * @param type the type of element that {@code c} is permitted to hold + * @return a dynamically typesafe view of the specified collection + * @since 1.5 + */ + public static Collection checkedCollection(Collection c, + Class type) { + return new CheckedCollection<>(c, type); + } + + @SuppressWarnings("unchecked") + static T[] zeroLengthArray(Class type) { + return (T[]) Array.newInstance(type, 0); + } /** * @serial include @@ -2706,6 +3156,7 @@ implements SortedSet, Serializable { private static final long serialVersionUID = 1599911165492914959L; + private final SortedSet ss; CheckedSortedSet(SortedSet s, Class type) { @@ -2728,6 +3179,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 +3462,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 +3845,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 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 /** @@ -3472,6 +4158,7 @@ * 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,216 +4212,433 @@ } /** - * Returns the empty sorted set (immutable). This set is serializable. + * 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 SortedSet emptySortedSet() { + return (SortedSet) EmptyNavigableSet.EMPTY_NAVIGABLE_SET; + } + + /** + * 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 + */ + @SuppressWarnings("unchecked") + public static NavigableSet emptyNavigableSet() { + return (NavigableSet) EmptyNavigableSet.EMPTY_NAVIGABLE_SET; + } + + /** + * The empty list (immutable). This list is serializable. + * + * @see #emptyList() + */ + @SuppressWarnings("rawtypes") + public static final List EMPTY_LIST = new EmptyList<>(); + + /** + * Returns the empty list (immutable). This list is serializable. * - *

This example illustrates the type-safe way to obtain an empty sorted - * set: + *

This example illustrates the type-safe way to obtain an empty list: *

-     *     SortedSet<String> s = Collections.emptySortedSet();
+     *     List<String> s = Collections.emptyList();
      * 
* Implementation note: Implementations of this method need not - * create a separate SortedSet object for each call. + * create a separate List 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.) * - * @since 1.8 + * @see #EMPTY_LIST + * @since 1.5 */ @SuppressWarnings("unchecked") - public static final SortedSet emptySortedSet() { - return (SortedSet) new EmptySortedSet<>(); + public static final List emptyList() { + return (List) EMPTY_LIST; } /** * @serial include */ - private static class EmptySortedSet - extends AbstractSet - implements SortedSet, Serializable - { - private static final long serialVersionUID = 6316515401502265487L; - public Iterator iterator() { return emptyIterator(); } + private static class EmptyList + extends AbstractList + implements RandomAccess, Serializable { + private static final long serialVersionUID = 8842843931221139166L; + + public Iterator iterator() { + return emptyIterator(); + } + public ListIterator listIterator() { + return emptyListIterator(); + } + 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) { + public T[] toArray(T[] a) { if (a.length > 0) a[0] = null; return a; } - // Preserves singleton property - private Object readResolve() { - return new EmptySortedSet<>(); + public E get(int index) { + throw new IndexOutOfBoundsException("Index: "+index); } - @Override - public Comparator comparator() { - return null; + public boolean equals(Object o) { + return (o instanceof List) && ((List)o).isEmpty(); } + public int hashCode() { return 1; } + @Override - @SuppressWarnings("unchecked") - public SortedSet subSet(Object fromElement, Object toElement) { - Objects.requireNonNull(fromElement); - Objects.requireNonNull(toElement); + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return false; + } + @Override + public void replaceAll(UnaryOperator operator) { + Objects.requireNonNull(operator); + } + @Override + public void sort(Comparator c) { + Objects.requireNonNull(c); + } - if (!(fromElement instanceof Comparable) || - !(toElement instanceof Comparable)) - { - throw new ClassCastException(); - } + // Override default methods in Collection + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + } - if ((((Comparable)fromElement).compareTo(toElement) >= 0) || - (((Comparable)toElement).compareTo(fromElement) < 0)) - { - throw new IllegalArgumentException(); - } + @Override + public Spliterator spliterator() { return Spliterators.emptySpliterator(); } - return emptySortedSet(); + // Preserves singleton property + private Object readResolve() { + return EMPTY_LIST; } + } - @Override - public SortedSet headSet(Object toElement) { - Objects.requireNonNull(toElement); + /** + * 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 { - if (!(toElement instanceof Comparable)) { - throw new ClassCastException(); - } + private static final long serialVersionUID = 5065418537829651507L; - return emptySortedSet(); + /** + * Our bounded keyset. + */ + final BoundedEmptyNavigableSet keySet; + + private BoundedEmptyNavigableMap(BoundedEmptyNavigableSet keySet) { + this.keySet = Objects.requireNonNull(keySet); } + public Comparator comparator() + { return keySet.comparator(); } + @Override - public SortedSet tailSet(Object fromElement) { - Objects.requireNonNull(fromElement); + public NavigableMap descendingMap() { + NavigableSet descending = keySet.descendingSet(); - if (!(fromElement instanceof Comparable)) { - throw new ClassCastException(); + if(descending == Collections.emptyNavigableSet()) { + return Collections.emptyNavigableMap(); + } else { + return new BoundedEmptyNavigableMap((BoundedEmptyNavigableSet) descending); } + } - return emptySortedSet(); + 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 E first() { - throw new NoSuchElementException(); + public NavigableMap headMap(K toKey, boolean inclusive) { + return new BoundedEmptyNavigableMap( + keySet.headSet(toKey, inclusive)); } @Override - public E last() { - throw new NoSuchElementException(); + 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 default methods in Collection @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); + 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); } - @Override - public boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter); - return false; + public BoundedEmptyNavigableSet headSet(E toElement, boolean inclusive) { + return new BoundedEmptyNavigableSet<>( + null, false, + (Comparable) Objects.requireNonNull(toElement), inclusive, + false); } - @Override - public Spliterator spliterator() { return Spliterators.emptySpliterator(); } - } + public BoundedEmptyNavigableSet tailSet(E fromElement, boolean inclusive) { + return new BoundedEmptyNavigableSet<>( + (Comparable) Objects.requireNonNull(fromElement), inclusive, + null, false, + false); + } - /** - * The empty list (immutable). This list is serializable. - * - * @see #emptyList() - */ - @SuppressWarnings("rawtypes") - public static final List EMPTY_LIST = new EmptyList<>(); + 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); } - /** - * Returns the empty list (immutable). This list is serializable. - * - *

This example illustrates the type-safe way to obtain an empty list: - *

-     *     List<String> s = Collections.emptyList();
-     * 
- * Implementation note: Implementations of this method need not - * create a separate List 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.) - * - * @see #EMPTY_LIST - * @since 1.5 - */ - @SuppressWarnings("unchecked") - public static final List emptyList() { - return (List) EMPTY_LIST; + public Comparator 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 EmptyList - extends AbstractList - implements RandomAccess, Serializable { - private static final long serialVersionUID = 8842843931221139166L; + private static class BoundedEmptyNavigableSet extends EmptyNavigableSet + implements Serializable { + private static final long serialVersionUID = 3393358742248855583L; - public Iterator iterator() { - return emptyIterator(); - } - public ListIterator listIterator() { - return emptyListIterator(); - } + /** + * {@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 int size() {return 0;} - public boolean isEmpty() {return true;} + 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)); - public boolean contains(Object obj) {return false;} - public boolean containsAll(Collection c) { return c.isEmpty(); } + if(fromCompared != -toCompared) { + throw new IllegalArgumentException("inconsistent compareTo"); + } - public Object[] toArray() { return new Object[0]; } + if (descending) { + if (fromCompared < 0) { + throw new IllegalArgumentException(); + } + } else { + if (fromCompared > 0) { + throw new IllegalArgumentException(); + } + } + } - public T[] toArray(T[] a) { - if (a.length > 0) - a[0] = null; - return a; + this.lowerBound = fromElement; + this.lowerInclusive = lowerInclusive; + this.upperBound = toElement; + this.upperInclusive = upperInclusive; } - public E get(int index) { - throw new IndexOutOfBoundsException("Index: "+index); - } + @Override + public Comparator 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"); + } + } + } - public boolean equals(Object o) { - return (o instanceof List) && ((List)o).isEmpty(); - } + 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"); + } + } + } - public int hashCode() { return 1; } + 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"); + } + } + } + } - @Override - public boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter); - return false; + return (Comparable) Objects.requireNonNull(element); } + @Override - public void replaceAll(UnaryOperator operator) { - Objects.requireNonNull(operator); + public EmptyNavigableSet descendingSet() { + if (upperBound == null && lowerBound == null && descending) { + return (EmptyNavigableSet) Collections.emptyNavigableSet(); + } + return new BoundedEmptyNavigableSet( + upperBound, upperInclusive, + lowerBound, lowerInclusive, + !descending); } + @Override - public void sort(Comparator c) { - Objects.requireNonNull(c); + public BoundedEmptyNavigableSet subSet(E fromKey, boolean fromInclusive, E toKey, boolean toInclusive) { + return new BoundedEmptyNavigableSet( + inBounds(fromKey), fromInclusive, + inBounds(toKey), toInclusive, + descending); } - // Override default methods in Collection @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); + public BoundedEmptyNavigableSet headSet(E toKey, boolean inclusive) { + return new BoundedEmptyNavigableSet( + lowerBound, lowerInclusive, + inBounds(Objects.requireNonNull(toKey)), inclusive, + descending); } @Override - public Spliterator spliterator() { return Spliterators.emptySpliterator(); } - - // Preserves singleton property - private Object readResolve() { - return EMPTY_LIST; + public BoundedEmptyNavigableSet tailSet(E fromKey, boolean inclusive) { + return new BoundedEmptyNavigableSet( + inBounds(Objects.requireNonNull(fromKey)), inclusive, + upperBound, upperInclusive, + descending); } } @@ -3750,7 +4654,7 @@ /** * 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();
      * 
@@ -3768,6 +4672,45 @@ } /** + * 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 +4801,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) descendingKeys); + } + } + + public EmptyNavigableSet navigableKeySet() + { return (EmptyNavigableSet) Collections.emptyNavigableSet(); } + public EmptyNavigableSet descendingKeySet() { + return navigableKeySet().descendingSet(); + } + + public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { + return new BoundedEmptyNavigableMap<>( + ((EmptyNavigableSet) Collections.emptyNavigableSet()).subSet( + fromKey, fromInclusive, + toKey, toInclusive)); + } + + public NavigableMap headMap(K toKey, boolean inclusive) { + return new BoundedEmptyNavigableMap<>( + ((EmptyNavigableSet) Collections.emptyNavigableSet()) + .headSet(toKey, inclusive)); + } + + public NavigableMap tailMap(K fromKey, boolean inclusive) { + return new BoundedEmptyNavigableMap<>( + ((EmptyNavigableSet) Collections.emptyNavigableSet()) + .tailSet(fromKey, inclusive)); + } + + public final SortedMap subMap(K fromKey, K toKey) + { return subMap(fromKey, true, toKey, false); } + + public final SortedMap headMap(K toKey) + { return headMap(toKey, true); } + + public final SortedMap tailMap(K fromKey) + { return tailMap(fromKey, false); } + + public Comparator comparator() { return null; } + } + // Singleton collections /** @@ -4661,6 +5727,122 @@ } /** + * Returns a navigable set backed by the specified map. The resulting + * navigable set displays the same ordering, concurrency, and performance + * characteristics as the backing map. In essence, this factory method + * provides a {@link NavigableSet} implementation corresponding to any + * {@link NavigableMap} implementation. There is no need to use this method + * on a {@link NavigableMap} implementation that already has a corresponding + * {@link Set} implementation (such as {@link TreeMap}). + * + *

Each method invocation on the set returned by this method results in + * exactly one method invocation on the backing map or its keySet + * view, with one exception. The addAll method is implemented + * as a sequence of put invocations on the backing map. + * + *

The specified map must be empty at the time this method is invoked, + * and should not be accessed directly after this method returns. These + * conditions are ensured if the map is created empty, passed directly + * to this method, and no reference to the map is retained, as illustrated + * in the following code fragment: + *

 {@code
+     *    Set weakHashSet = Collections.newNavigableSetFromNavigableMap(
+     *        new WeakHashMap());
+     * }
+     *
+     * @param map the backing navigable map
+     * @return the navigable set backed by the map
+     * @throws IllegalArgumentException if map is not empty
+     * @since 1.8
+     */
+    public static  NavigableSet newNavigableSetFromNavigableMap(NavigableMap map) {
+        return new NavigableSetFromNavigableMap<>(map);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class NavigableSetFromNavigableMap extends AbstractSet
+        implements NavigableSet, Serializable
+    {
+        private static final long serialVersionUID = -7303807726339382839L;
+
+        private final NavigableMap m;  // The backing map
+        private transient NavigableSet s;       // Its keySet
+
+        NavigableSetFromNavigableMap(NavigableMap map) {
+            if (!map.isEmpty())
+                throw new IllegalArgumentException("Map is non-empty");
+            m = map;
+            s = map.navigableKeySet();
+        }
+
+        public void clear()               {        m.clear(); }
+        public int size()                 { return m.size(); }
+        public boolean isEmpty()          { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o)   { return m.remove(o) != null; }
+        public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
+        public Iterator iterator()     { return s.iterator(); }
+        public Object[] toArray()         { return s.toArray(); }
+        public  T[] toArray(T[] a)     { return s.toArray(a); }
+        public String toString()          { return s.toString(); }
+        public int hashCode()             { return s.hashCode(); }
+        public boolean equals(Object o)   { return o == this || s.equals(o); }
+        public boolean containsAll(Collection c) {return s.containsAll(c);}
+        public boolean removeAll(Collection c)   {return s.removeAll(c);}
+        public boolean retainAll(Collection c)   {return s.retainAll(c);}
+        // addAll is the only inherited implementation
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer action)  { s.forEach(action); }
+        @Override
+        public boolean removeIf(Predicate filter) {
+            return s.removeIf(filter);
+        }
+
+        @Override
+        public Spliterator spliterator()            {return s.spliterator();}
+
+        private void readObject(java.io.ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+            stream.defaultReadObject();
+            if (null == m) {
+                throw new InvalidObjectException("null map");
+            }
+            s = m.navigableKeySet();
+        }
+
+        public E lower(E e)                           { return m.lowerKey(e); }
+        public E floor(E e)                           { return m.floorKey(e); }
+        public E ceiling(E e)                       { return m.ceilingKey(e); }
+        public E higher(E e)                         { return m.higherKey(e); }
+        public E pollFirst()                          { return s.pollFirst(); }
+        public E pollLast()                            { return s.pollLast(); }
+        public NavigableSet descendingSet()    { return s.descendingSet(); }
+        public Iterator descendingIterator(){return s.descendingIterator();}
+
+        public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return s.subSet(fromElement, fromInclusive, toElement, toInclusive);
+        }
+
+        public NavigableSet headSet(E toElement, boolean inclusive)
+                                    { return s.headSet(toElement, inclusive); }
+        public NavigableSet tailSet(E fromElement, boolean inclusive)
+                                  { return s.tailSet(fromElement, inclusive); }
+        public SortedSet subSet(E fromElement, E toElement)
+                                   { return s.subSet(fromElement, toElement); }
+        public SortedSet headSet(E toElement)
+                                               { return s.headSet(toElement); }
+        public SortedSet tailSet(E fromElement)
+                                             { return s.tailSet(fromElement); }
+        public Comparator comparator()    { return s.comparator(); }
+        public E first()                                  { return s.first(); }
+        public E last()                                    { return s.last(); }
+    }
+
+    /**
      * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo)
      * {@link Queue}. Method add is mapped to push,
      * remove is mapped to pop and so on. This