--- old/src/share/classes/java/util/Collections.java 2013-04-29 18:49:47.190575358 -0700 +++ new/src/share/classes/java/util/Collections.java 2013-04-29 18:49:46.994575349 -0700 @@ -1212,6 +1212,70 @@ } /** + * 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 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 @@ -1670,6 +1734,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 SortedMap unmodifiableNavigableMap(NavigableMap m) { + return new UnmodifiableNavigableMap<>(m); + } + + /** + * @serial include + */ + static class UnmodifiableNavigableMap + extends UnmodifiableSortedMap + implements NavigableMap, Serializable { + // private static final long serialVersionUID = -8806743815996713206L; + + 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 (NavigableMap) 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 (NavigableMap) unmodifiableNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive)); + } + + @Override + public NavigableMap headMap(K toKey, boolean inclusive) { + return (NavigableMap) unmodifiableNavigableMap(nm.headMap(toKey, inclusive)); + } + + @Override + public NavigableMap tailMap(K fromKey, boolean inclusive) { + return (NavigableMap) unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive)); + } + } // Synch Wrappers @@ -1945,6 +2134,110 @@ } /** + * 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 subSet, + * headSet, or 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 = 8695801310862127406L; + + private final NavigableSet ns; + + SynchronizedNavigableSet(NavigableSet s) { + super(s); + ns = s; + } + SynchronizedNavigableSet(NavigableSet s, Object mutex) { + super(s, mutex); + ns = s; + } + @Override public E lower(E e) { synchronized (mutex) {return ns.lower(e);} } + @Override public E floor(E e) { synchronized (mutex) {return ns.floor(e);} } + @Override public E ceiling(E e) { synchronized (mutex) {return ns.ceiling(e);} } + @Override public E higher(E e) { synchronized (mutex) {return ns.higher(e);} } + @Override public E pollFirst() { synchronized (mutex) {return ns.pollFirst();} } + @Override public E pollLast() { synchronized (mutex) {return ns.pollLast();} } + @Override + public NavigableSet descendingSet() { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex); + } + } + + @Override + public Iterator descendingIterator() { + synchronized (mutex) { + return descendingSet().iterator(); + } + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex); + } + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex); + } + } + + @Override + 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 @@ -2384,71 +2677,249 @@ } } - // 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 subMap, headMap or + * 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); + } + + + /** + * @serial include + */ + static class SynchronizedNavigableMap + extends SynchronizedSortedMap + implements NavigableMap + { + private static final long serialVersionUID = -8798146769416483793L; + + private final NavigableMap nm; + + SynchronizedNavigableMap(NavigableMap m) { + super(m); + nm = m; + } + SynchronizedNavigableMap(NavigableMap m, Object mutex) { + super(m, mutex); + nm = m; + } + + @Override + public Entry lowerEntry(K key) { + synchronized (mutex) { return nm.lowerEntry(key); } + } + + @Override + public K lowerKey(K key) { + synchronized (mutex) { return nm.lowerKey(key); } + } + + @Override + public Entry floorEntry(K key) { + synchronized (mutex) { return nm.floorEntry(key); } + } + + @Override + public K floorKey(K key) { + synchronized (mutex) { return nm.floorKey(key); } + } + + @Override + public Entry ceilingEntry(K key) { + synchronized (mutex) { return nm.ceilingEntry(key); } + } + + @Override + 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) { + Entry entry = (Entry) nm.pollFirstEntry(); + return (null == entry) ? null : entry; + } + } + + @Override + public Entry pollLastEntry() { + synchronized (mutex) { + Entry entry = (Entry) nm.pollLastEntry(); + return (null == entry) ? null : entry; + } + } + + @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") @@ -2728,6 +3199,108 @@ } } +/** + * 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 = 1599911165492914959L; + private final NavigableSet ns; + + CheckedNavigableSet(NavigableSet s, Class type) { + super(s, type); + 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() { + return ns.pollFirst(); + } + + @Override + public E pollLast() { + return ns.pollLast(); + } + + @Override + public NavigableSet descendingSet() { + return checkedNavigableSet(ns.descendingSet(), type); + } + + @Override + public Iterator descendingIterator() { + return checkedNavigableSet(ns.descendingSet(), type).iterator(); + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type); + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + return checkedNavigableSet(ns.headSet(toElement, inclusive), type); + } + + @Override + 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 @@ -3325,31 +3898,195 @@ } } - // Empty collections - /** - * Returns an iterator that has no elements. More precisely, - * - *

+ *

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

Implementations of this method are permitted, but not - * required, to return the same object from multiple invocations. + *

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. * - * @return an empty iterator - * @since 1.7 + * @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 */ - @SuppressWarnings("unchecked") + 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 = 1599671320688067438L; + + 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 + + /** + * Returns an iterator that has no elements. More precisely, + * + *

+ * + *

Implementations of this method are permitted, but not + * required, to return the same object from multiple invocations. + * + * @return an empty iterator + * @since 1.7 + */ + @SuppressWarnings("unchecked") public static Iterator emptyIterator() { return (Iterator) EmptyIterator.EMPTY_ITERATOR; } @@ -3524,48 +4261,64 @@ } } + private static final EmptyNavigableSet EMPTY_NAVIGABLE_SET = + new EmptyNavigableSet<>(); + /** * 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. + *

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. * * @since 1.8 */ @SuppressWarnings("unchecked") - public static final SortedSet emptySortedSet() { - return (SortedSet) new EmptySortedSet<>(); + public static SortedSet emptySortedSet() { + return (SortedSet) EMPTY_NAVIGABLE_SET; + } + + /** + * Returns the 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. + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static NavigableSet emptyNavigableSet() { + return (NavigableSet) EMPTY_NAVIGABLE_SET; } /** * @serial include */ - private static class EmptySortedSet - extends AbstractSet - implements SortedSet, Serializable + private static class EmptyNavigableSet + extends EmptySet + implements NavigableSet, 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]; } + // private static final long serialVersionUID = 6316515401502265487L; - public E[] toArray(E[] a) { - if (a.length > 0) - a[0] = null; - return a; + public boolean contains(Object obj) { + Comparable e = (Comparable) obj; + return obj != e; } // Preserves singleton property private Object readResolve() { - return new EmptySortedSet<>(); + return Collections.emptyNavigableSet(); } @Override @@ -3575,55 +4328,93 @@ @Override @SuppressWarnings("unchecked") - public SortedSet subSet(Object fromElement, Object toElement) { - Objects.requireNonNull(fromElement); - Objects.requireNonNull(toElement); + public SortedSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } - if (!(fromElement instanceof Comparable) || - !(toElement instanceof Comparable)) - { - throw new ClassCastException(); - } + @Override + public SortedSet headSet(E toElement) { + return headSet(toElement, false); + } - if ((((Comparable)fromElement).compareTo(toElement) >= 0) || - (((Comparable)toElement).compareTo(fromElement) < 0)) - { - throw new IllegalArgumentException(); - } + @Override + public SortedSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } - return emptySortedSet(); + @Override + public E first() { + throw new NoSuchElementException(); } @Override - public SortedSet headSet(Object toElement) { - Objects.requireNonNull(toElement); + public E last() { + throw new NoSuchElementException(); + } - if (!(toElement instanceof Comparable)) { - throw new ClassCastException(); - } + @Override + public E lower(E e) { + Objects.requireNonNull(e); + return null; + } - return emptySortedSet(); + @Override + public E floor(E e) { + Objects.requireNonNull(e); + return null; } @Override - public SortedSet tailSet(Object fromElement) { - Objects.requireNonNull(fromElement); + public E ceiling(E e) { + Objects.requireNonNull(e); + return null; + } - if (!(fromElement instanceof Comparable)) { - throw new ClassCastException(); - } + @Override + public E higher(E e) { + Objects.requireNonNull(e); + return null; + } - return emptySortedSet(); + @Override + public E pollFirst() { + return null; } @Override - public E first() { - throw new NoSuchElementException(); + public E pollLast() { + return null; } @Override - public E last() { - throw new NoSuchElementException(); + public NavigableSet descendingSet() { + return new BoundedEmptyNavigableSet(null, true, null, true, true); + } + + @Override + public Iterator descendingIterator() { return emptyIterator(); } + + @Override + public NavigableSet 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 NavigableSet headSet(E toElement, boolean inclusive) { + return new BoundedEmptyNavigableSet( + null, true, + (Comparable) Objects.requireNonNull(toElement), inclusive, + false); + } + + @Override + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return new BoundedEmptyNavigableSet( + (Comparable) Objects.requireNonNull(fromElement), inclusive, + null, true, false); } // Override default methods in Collection @@ -3738,6 +4529,270 @@ } } + private static class BoundedEmptyNavigableSet extends EmptyNavigableSet + implements Serializable { + + final boolean descending; + final boolean lowerInclusive; + final boolean upperInclusive; + final Comparable lowerBound; + final Comparable upperBound; + + public BoundedEmptyNavigableSet( + Comparable fromElement, boolean lowerInclusive, + Comparable toElement, boolean upperInclusive, + boolean descending) { + this.descending = descending; + + if ((fromElement != null) && (toElement != null)) { + 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 comparator() { + return descending ? Collections.reverseOrder() : null; + } + + public NavigableSet descendingSet() { + return new BoundedEmptyNavigableSet(upperBound, upperInclusive, lowerBound, lowerInclusive, !descending); + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + return new BoundedEmptyNavigableSet(inBounds(fromElement), fromInclusive, inBounds(toElement), toInclusive, descending); + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + return new BoundedEmptyNavigableSet(lowerBound, lowerInclusive, inBounds(toElement), inclusive, descending); + } + + @Override + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return new BoundedEmptyNavigableSet(inBounds(fromElement), inclusive, upperBound, upperInclusive, descending); + } + + 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); + } + } + +private static class BoundedEmptyNavigableMap extends EmptyNavigableMap + implements Serializable { + + final boolean descending; + final boolean lowerInclusive; + final boolean upperInclusive; + final Comparable lowerBound; + final Comparable upperBound; + + public BoundedEmptyNavigableMap( + Comparable fromElement, boolean lowerInclusive, + Comparable toElement, boolean upperInclusive, + boolean descending) { + this.descending = descending; + + if ((fromElement != null) && (toElement != null)) { + int fromCompared = Integer.signum(fromElement.compareTo((K)toElement)); + int toCompared = Integer.signum(toElement.compareTo((K)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 comparator() { + return descending ? Collections.reverseOrder() : null; + } + + @Override + public boolean containsKey(Object obj) { + Comparable e = (Comparable) obj; + return obj != e; + } + + private Comparable inBounds(K 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 NavigableMap descendingMap() { + if (upperBound == null && lowerBound == null && descending) { + return Collections.emptyNavigableMap(); + } + return new BoundedEmptyNavigableMap(upperBound, upperInclusive, lowerBound, lowerInclusive, !descending); + } + + @Override + public NavigableSet navigableKeySet() { + if (upperBound == null && lowerBound == null && !descending) { + return Collections.emptyNavigableSet(); + } + return new BoundedEmptyNavigableSet(lowerBound, lowerInclusive, upperBound, upperInclusive, descending); + } + + @Override + public NavigableSet descendingKeySet() { + if (upperBound == null && lowerBound == null && descending) { + return Collections.emptyNavigableSet(); + } + return new BoundedEmptyNavigableSet(upperBound, upperInclusive, lowerBound, lowerInclusive, !descending); + } + + @Override + public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { + return new BoundedEmptyNavigableMap(inBounds(fromKey), fromInclusive, inBounds(toKey), toInclusive, descending); + } + + @Override + public NavigableMap headMap(K toKey, boolean inclusive) { + return new BoundedEmptyNavigableMap(lowerBound, lowerInclusive, inBounds(toKey), inclusive, descending); + } + + @Override + public NavigableMap tailMap(K fromKey, boolean inclusive) { + return new BoundedEmptyNavigableMap(inBounds(fromKey), inclusive, upperBound, upperInclusive, descending); + } + } + /** * The empty map (immutable). This map is serializable. * @@ -3750,7 +4805,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 +4823,46 @@ } /** + * Returns the 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. + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static final SortedMap emptySortedMap() { + return (SortedMap) EMPTY_NAVIGABLE_MAP; + } + + @SuppressWarnings("rawtypes") + private static final NavigableMap EMPTY_NAVIGABLE_MAP = + new EmptyNavigableMap(); + + /** + * Returns the 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. + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static final NavigableMap emptyNavigableMap() { + return (NavigableMap) EMPTY_NAVIGABLE_MAP; + } + + /** * @serial include */ private static class EmptyMap @@ -3858,6 +4953,139 @@ } } + private static class EmptyNavigableMap extends EmptyMap + implements NavigableMap, Serializable { + + EmptyNavigableMap() { + + } + + // Preserves singleton property + private Object readResolve() { + return Collections.emptyNavigableMap(); + } + + @Override + public Entry lowerEntry(K key) { + return null; + } + + @Override + public K lowerKey(K key) { + return null; + } + + @Override + public Entry floorEntry(K key) { + return null; + } + + @Override + public K floorKey(K key) { + return null; + } + + @Override + public Entry ceilingEntry(K key) { + return null; + } + + @Override + public K ceilingKey(K key) { + return null; + } + + @Override + public Entry higherEntry(K key) { + return null; + } + + @Override + public K higherKey(K key) { + return null; + } + + @Override + public Entry firstEntry() { + return null; + } + + @Override + public Entry lastEntry() { + return null; + } + + @Override + public Entry pollFirstEntry() { + throw new UnsupportedOperationException(); + } + + @Override + public Entry pollLastEntry() { + throw new UnsupportedOperationException(); + } + + @Override + public NavigableMap descendingMap() { + return new BoundedEmptyNavigableMap<>(null, true, null, true, true); + } + + @Override + public NavigableSet navigableKeySet() { + return Collections.emptyNavigableSet(); + } + + @Override + public NavigableSet descendingKeySet() { + return Collections.emptyNavigableSet().descendingSet(); + } + + @Override + public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { + return new BoundedEmptyNavigableMap<>((Comparable) fromKey, fromInclusive, (Comparable) toKey, toInclusive, false); + } + + @Override + public NavigableMap headMap(K toKey, boolean inclusive) { + return new BoundedEmptyNavigableMap<>(null, false, (Comparable) toKey, inclusive, false); + } + + @Override + public NavigableMap tailMap(K fromKey, boolean inclusive) { + return new BoundedEmptyNavigableMap<>((Comparable) fromKey, inclusive, null, false, false); + } + + @Override + public SortedMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + @Override + public SortedMap headMap(K toKey) { + return headMap(toKey, false); + } + + @Override + public SortedMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + @Override + public Comparator comparator() { + return null; + } + + @Override + public K firstKey() { + return null; + } + + @Override + public K lastKey() { + return null; + } + } + // Singleton collections /**