src/share/classes/java/util/Collections.java
Print this page
rev 7019 : 7129185: Add Collections.{checked|empty|unmodifiable}Navigable{Map|Set}
Reviewed-by: duke
@@ -1210,10 +1210,74 @@
public E first() {return ss.first();}
public E last() {return ss.last();}
}
/**
+ * 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
+ * <tt>subSet</tt>, <tt>headSet</tt>, or <tt>tailSet</tt> views, result in
+ * an <tt>UnsupportedOperationException</tt>.<p>
+ *
+ * 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 <T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s) {
+ return new UnmodifiableNavigableSet<>(s);
+ }
+
+ /**
+ * @serial include
+ */
+ static class UnmodifiableNavigableSet<E>
+ extends UnmodifiableSortedSet<E>
+ implements NavigableSet<E>, Serializable {
+
+ private final NavigableSet<E> ns;
+
+ UnmodifiableNavigableSet(NavigableSet<E> 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<E> descendingSet() {
+ return new UnmodifiableNavigableSet<>(ns.descendingSet());
+ }
+
+ @Override
+ public Iterator<E> descendingIterator() {
+ return descendingSet().iterator();
+ }
+
+ @Override
+ public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return new UnmodifiableNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
+ }
+
+ @Override
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return new UnmodifiableNavigableSet<>(ns.headSet(toElement, inclusive));
+ }
+
+ @Override
+ public NavigableSet<E> 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
* specified list, and attempts to modify the returned list, whether
* direct or via its iterator, result in an
@@ -1668,10 +1732,135 @@
public K firstKey() {return sm.firstKey();}
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
+ * <tt>subMap</tt>, <tt>headMap</tt>, or <tt>tailMap</tt> views, result in
+ * an <tt>UnsupportedOperationException</tt>.<p>
+ *
+ * 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 <K,V> SortedMap<K,V> unmodifiableNavigableMap(NavigableMap<K, ? extends V> m) {
+ return new UnmodifiableNavigableMap<>(m);
+ }
+
+ /**
+ * @serial include
+ */
+ static class UnmodifiableNavigableMap<K,V>
+ extends UnmodifiableSortedMap<K,V>
+ implements NavigableMap<K,V>, Serializable {
+ // private static final long serialVersionUID = -8806743815996713206L;
+
+ private final NavigableMap<K, ? extends V> nm;
+
+ UnmodifiableNavigableMap(NavigableMap<K, ? extends V> m) {super(m); nm = m;}
+
+ @Override
+ public Entry<K, V> lowerEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.lowerEntry(key));
+ }
+
+ @Override
+ public K lowerKey(K key) {
+ return nm.lowerKey(key);
+ }
+
+ @Override
+ public Entry<K, V> floorEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.floorEntry(key));
+ }
+
+ @Override
+ public K floorKey(K key) {
+ return nm.floorKey(key);
+ }
+
+ @Override
+ public Entry<K, V> ceilingEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.ceilingEntry(key));
+ }
+
+ @Override
+ public K ceilingKey(K key) {
+ return nm.ceilingKey(key);
+ }
+
+ @Override
+ public Entry<K, V> higherEntry(K key) {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.higherEntry(key));
+ }
+
+ @Override
+ public K higherKey(K key) {
+ return nm.higherKey(key);
+ }
+
+ @Override
+ public Entry<K, V> firstEntry() {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.firstEntry());
+ }
+
+ @Override
+ public Entry<K, V> lastEntry() {
+ return new UnmodifiableEntrySet.UnmodifiableEntry(nm.lastEntry());
+ }
+
+ @Override
+ public Entry<K, V> pollFirstEntry() {
+ Entry<K,V> entry = (Entry<K,V>) nm.pollFirstEntry();
+ return (null == entry) ? null : new UnmodifiableEntrySet.UnmodifiableEntry(entry);
+ }
+
+ @Override
+ public Entry<K, V> pollLastEntry() {
+ Entry<K,V> entry = (Entry<K,V>) nm.pollLastEntry();
+ return (null == entry) ? null : new UnmodifiableEntrySet.UnmodifiableEntry(entry);
+ }
+
+ @Override
+ public NavigableMap<K, V> descendingMap() {
+ return (NavigableMap<K,V>) unmodifiableNavigableMap(nm.descendingMap());
+ }
+
+ @Override
+ public NavigableSet<K> navigableKeySet() {
+ return unmodifiableNavigableSet(nm.navigableKeySet());
+ }
+
+ @Override
+ public NavigableSet<K> descendingKeySet() {
+ return unmodifiableNavigableSet(nm.descendingKeySet());
+ }
+
+ @Override
+ public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return (NavigableMap<K,V>) unmodifiableNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive));
+ }
+
+ @Override
+ public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+ return (NavigableMap<K,V>) unmodifiableNavigableMap(nm.headMap(toKey, inclusive));
+ }
+
+ @Override
+ public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+ return (NavigableMap<K,V>) unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive));
+ }
+ }
// Synch Wrappers
/**
* Returns a synchronized (thread-safe) collection backed by the specified
@@ -1943,10 +2132,114 @@
synchronized (mutex) {return ss.last();}
}
}
/**
+ * Returns a synchronized (thread-safe) sorted set backed by the specified
+ * navigable set. In order to guarantee serial access, it is critical that
+ * <strong>all</strong> access to the backing sorted set is accomplished
+ * through the returned navigable set (or its views).<p>
+ *
+ * It is imperative that the user manually synchronize on the returned
+ * navigable set when iterating over it or any of its <tt>subSet</tt>,
+ * <tt>headSet</tt>, or <tt>tailSet</tt> views.
+ * <pre>
+ * SortedSet s = Collections.synchronizedNavigableSet(new TreeSet());
+ * ...
+ * synchronized (s) {
+ * Iterator i = s.iterator(); // Must be in the synchronized block
+ * while (i.hasNext())
+ * foo(i.next());
+ * }
+ * </pre>
+ * or:
+ * <pre>
+ * 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());
+ * }
+ * </pre>
+ * Failure to follow this advice may result in non-deterministic behavior.
+ *
+ * <p>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 <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s) {
+ return new SynchronizedNavigableSet<>(s);
+ }
+
+ /**
+ * @serial include
+ */
+ static class SynchronizedNavigableSet<E>
+ extends SynchronizedSortedSet<E>
+ implements NavigableSet<E>
+ {
+ //private static final long serialVersionUID = 8695801310862127406L;
+
+ private final NavigableSet<E> ns;
+
+ SynchronizedNavigableSet(NavigableSet<E> s) {
+ super(s);
+ ns = s;
+ }
+ SynchronizedNavigableSet(NavigableSet<E> 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<E> descendingSet() {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex);
+ }
+ }
+
+ @Override
+ public Iterator<E> descendingIterator() {
+ synchronized (mutex) {
+ return descendingSet().iterator();
+ }
+ }
+
+ @Override
+ public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex);
+ }
+ }
+
+ @Override
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex);
+ }
+ }
+
+ @Override
+ public NavigableSet<E> 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
* <strong>all</strong> access to the backing list is accomplished
* through the returned list.<p>
*
@@ -2382,73 +2675,251 @@
public K lastKey() {
synchronized (mutex) {return sm.lastKey();}
}
}
- // 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
- * <i>guaranteed</i> that the collection cannot contain an incorrectly
- * typed element.
- *
- * <p>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.
- *
- * <p>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:
- * <pre> {@code
- * Collection<String> c = new HashSet<String>();
- * }</pre>
- * may be replaced temporarily by this one:
- * <pre> {@code
- * Collection<String> c = Collections.checkedCollection(
- * new HashSet<String>(), String.class);
- * }</pre>
- * 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.
- *
- * <p>The returned collection does <i>not</i> 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 <strong>all</strong> access to the backing navigable map is
+ * accomplished through the returned navigable map (or its views).<p>
*
- * <p>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 <tt>subMap</tt>, <tt>headMap</tt> or
+ * <tt>tailMap</tt> views.
+ * <pre>
+ * 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());
+ * }
+ * </pre>
+ * or:
+ * <pre>
+ * 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());
+ * }
+ * </pre>
+ * Failure to follow this advice may result in non-deterministic behavior.
*
- * <p>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.
+ * <p>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 <E> Collection<E> checkedCollection(Collection<E> c,
+ public static <K,V> NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m) {
+ return new SynchronizedNavigableMap<>(m);
+ }
+
+
+ /**
+ * @serial include
+ */
+ static class SynchronizedNavigableMap<K,V>
+ extends SynchronizedSortedMap<K,V>
+ implements NavigableMap<K,V>
+ {
+ private static final long serialVersionUID = -8798146769416483793L;
+
+ private final NavigableMap<K,V> nm;
+
+ SynchronizedNavigableMap(NavigableMap<K,V> m) {
+ super(m);
+ nm = m;
+ }
+ SynchronizedNavigableMap(NavigableMap<K,V> m, Object mutex) {
+ super(m, mutex);
+ nm = m;
+ }
+
+ @Override
+ public Entry<K, V> lowerEntry(K key) {
+ synchronized (mutex) { return nm.lowerEntry(key); }
+ }
+
+ @Override
+ public K lowerKey(K key) {
+ synchronized (mutex) { return nm.lowerKey(key); }
+ }
+
+ @Override
+ public Entry<K, V> floorEntry(K key) {
+ synchronized (mutex) { return nm.floorEntry(key); }
+ }
+
+ @Override
+ public K floorKey(K key) {
+ synchronized (mutex) { return nm.floorKey(key); }
+ }
+
+ @Override
+ public Entry<K, V> ceilingEntry(K key) {
+ synchronized (mutex) { return nm.ceilingEntry(key); }
+ }
+
+ @Override
+ public K ceilingKey(K key) {
+ synchronized (mutex) { return nm.ceilingKey(key); }
+ }
+
+ @Override
+ public Entry<K, V> higherEntry(K key) {
+ synchronized (mutex) { return nm.higherEntry(key); }
+ }
+
+ @Override
+ public K higherKey(K key) {
+ synchronized (mutex) { return nm.higherKey(key); }
+ }
+
+ @Override
+ public Entry<K, V> firstEntry() {
+ synchronized (mutex) { return nm.firstEntry(); }
+ }
+
+ @Override
+ public Entry<K, V> lastEntry() {
+ synchronized (mutex) { return nm.lastEntry(); }
+ }
+
+ @Override
+ public Entry<K, V> pollFirstEntry() {
+ synchronized (mutex) {
+ Entry<K,V> entry = (Entry<K,V>) nm.pollFirstEntry();
+ return (null == entry) ? null : entry;
+ }
+ }
+
+ @Override
+ public Entry<K, V> pollLastEntry() {
+ synchronized (mutex) {
+ Entry<K,V> entry = (Entry<K,V>) nm.pollLastEntry();
+ return (null == entry) ? null : entry;
+ }
+ }
+
+ @Override
+ public NavigableMap<K, V> descendingMap() {
+ synchronized (mutex) {
+ return (NavigableMap<K,V>) new SynchronizedNavigableMap(nm.descendingMap(), mutex);
+ }
+ }
+
+ @Override
+ public NavigableSet<K> navigableKeySet() {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet(nm.navigableKeySet(), mutex);
+ }
+ }
+
+ @Override
+ public NavigableSet<K> descendingKeySet() {
+ synchronized (mutex) {
+ return new SynchronizedNavigableSet(nm.descendingKeySet(), mutex);
+ }
+ }
+
+ @Override
+ public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ synchronized (mutex) {
+ return (NavigableMap<K,V>) new SynchronizedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), mutex);
+ }
+ }
+
+ @Override
+ public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+ synchronized (mutex) {
+ return (NavigableMap<K,V>) new SynchronizedNavigableMap(nm.headMap(toKey, inclusive), mutex);
+ }
+ }
+
+ @Override
+ public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+ synchronized (mutex) {
+ return (NavigableMap<K,V>) 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
+ * <i>guaranteed</i> that the collection cannot contain an incorrectly
+ * typed element.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre> {@code
+ * Collection<String> c = new HashSet<String>();
+ * }</pre>
+ * may be replaced temporarily by this one:
+ * <pre> {@code
+ * Collection<String> c = Collections.checkedCollection(
+ * new HashSet<String>(), String.class);
+ * }</pre>
+ * 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.
+ *
+ * <p>The returned collection does <i>not</i> 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.
+ *
+ * <p>The returned collection will be serializable if the specified
+ * collection is serializable.
+ *
+ * <p>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 <E> Collection<E> checkedCollection(Collection<E> c,
Class<E> type) {
return new CheckedCollection<>(c, type);
}
@SuppressWarnings("unchecked")
@@ -2726,10 +3197,112 @@
public SortedSet<E> tailSet(E fromElement) {
return checkedSortedSet(ss.tailSet(fromElement), type);
}
}
+/**
+ * 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
+ * <em>guaranteed</em> that the navigable set cannot contain an incorrectly
+ * typed element.
+ *
+ * <p>A discussion of the use of dynamically typesafe views may be
+ * found in the documentation for the {@link #checkedCollection
+ * checkedCollection} method.
+ *
+ * <p>The returned navigable set will be serializable if the specified
+ * navigable set is serializable.
+ *
+ * <p>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 <E> NavigableSet<E> checkedNavigableSet(NavigableSet<E> s,
+ Class<E> type) {
+ return new CheckedNavigableSet<>(s, type);
+ }
+
+ /**
+ * @serial include
+ */
+ static class CheckedNavigableSet<E> extends CheckedSortedSet<E>
+ implements NavigableSet<E>, Serializable
+ {
+ //private static final long serialVersionUID = 1599911165492914959L;
+ private final NavigableSet<E> ns;
+
+ CheckedNavigableSet(NavigableSet<E> s, Class<E> 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<E> descendingSet() {
+ return checkedNavigableSet(ns.descendingSet(), type);
+ }
+
+ @Override
+ public Iterator<E> descendingIterator() {
+ return checkedNavigableSet(ns.descendingSet(), type).iterator();
+ }
+
+ @Override
+ public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type);
+ }
+
+ @Override
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return checkedNavigableSet(ns.headSet(toElement, inclusive), type);
+ }
+
+ @Override
+ public NavigableSet<E> 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
* an immediate {@link ClassCastException}. Assuming a list contains
* no incorrectly typed elements prior to the time a dynamically typesafe
@@ -3323,37 +3896,201 @@
public SortedMap<K,V> tailMap(K fromKey) {
return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType);
}
}
- // Empty collections
-
/**
- * Returns an iterator that has no elements. More precisely,
- *
- * <ul compact>
- *
- * <li>{@link Iterator#hasNext hasNext} always returns {@code
- * false}.
+ * 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.
*
- * <li>{@link Iterator#next next} always throws {@link
- * NoSuchElementException}.
+ * <p>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 <em>guaranteed</em> that the
+ * map cannot contain an incorrectly typed key or value.
*
- * <li>{@link Iterator#remove remove} always throws {@link
- * IllegalStateException}.
+ * <p>A discussion of the use of dynamically typesafe views may be
+ * found in the documentation for the {@link #checkedCollection
+ * checkedCollection} method.
*
- * </ul>
+ * <p>The returned map will be serializable if the specified map is
+ * serializable.
*
- * <p>Implementations of this method are permitted, but not
- * required, to return the same object from multiple invocations.
+ * <p>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 <T> Iterator<T> emptyIterator() {
- return (Iterator<T>) EmptyIterator.EMPTY_ITERATOR;
+ public static <K,V> NavigableMap<K,V> checkedNavigableMap(NavigableMap<K, V> m,
+ Class<K> keyType,
+ Class<V> valueType) {
+ return new CheckedNavigableMap<>(m, keyType, valueType);
+ }
+
+ /**
+ * @serial include
+ */
+ static class CheckedNavigableMap<K,V> extends CheckedSortedMap<K,V>
+ implements NavigableMap<K,V>, Serializable
+ {
+ //private static final long serialVersionUID = 1599671320688067438L;
+
+ private final NavigableMap<K, V> nm;
+
+ CheckedNavigableMap(NavigableMap<K, V> m,
+ Class<K> keyType, Class<V> valueType) {
+ super(m, keyType, valueType);
+ nm = m;
+ }
+
+ public Comparator<? super K> comparator() { return nm.comparator(); }
+ public K firstKey() { return nm.firstKey(); }
+ public K lastKey() { return nm.lastKey(); }
+
+ public NavigableMap<K,V> subMap(K fromKey, K toKey) {
+ return checkedNavigableMap((NavigableMap<K,V>)nm.subMap(fromKey, toKey),
+ keyType, valueType);
+ }
+ public NavigableMap<K,V> headMap(K toKey) {
+ return checkedNavigableMap((NavigableMap<K,V>)nm.headMap(toKey), keyType, valueType);
+ }
+ public NavigableMap<K,V> tailMap(K fromKey) {
+ return checkedNavigableMap((NavigableMap<K,V>)nm.tailMap(fromKey), keyType, valueType);
+ }
+
+ @Override
+ public Entry<K, V> 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<K, V> 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<K, V> 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<K, V> 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<K, V> firstEntry() {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.firstEntry(), valueType);
+ }
+
+ @Override
+ public Entry<K, V> lastEntry() {
+ return new CheckedMap.CheckedEntrySet.CheckedEntry(nm.lastEntry(), valueType);
+ }
+
+ @Override
+ public Entry<K, V> pollFirstEntry() {
+ Entry<K,V> entry = nm.pollFirstEntry();
+ return (null == entry) ? null : new CheckedMap.CheckedEntrySet.CheckedEntry(entry, valueType);
+ }
+
+ @Override
+ public Entry<K, V> pollLastEntry() {
+ Entry<K,V> entry = nm.pollLastEntry();
+ return (null == entry) ? null : new CheckedMap.CheckedEntrySet.CheckedEntry(entry, valueType);
+ }
+
+ @Override
+ public NavigableMap<K, V> descendingMap() {
+ return checkedNavigableMap(nm.descendingMap(), keyType, valueType);
+ }
+
+ @Override
+ public NavigableSet<K> navigableKeySet() {
+ return checkedNavigableSet(nm.navigableKeySet(), keyType);
+ }
+
+ @Override
+ public NavigableSet<K> descendingKeySet() {
+ return checkedNavigableSet(nm.descendingKeySet(), keyType);
+ }
+
+ @Override
+ public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return checkedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), keyType, valueType);
+ }
+
+ @Override
+ public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+ return checkedNavigableMap(nm.headMap(toKey, inclusive), keyType, valueType);
+ }
+
+ @Override
+ public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+ return checkedNavigableMap(nm.tailMap(fromKey, inclusive), keyType, valueType);
+ }
+ }
+
+ // Empty collections
+
+ /**
+ * Returns an iterator that has no elements. More precisely,
+ *
+ * <ul compact>
+ *
+ * <li>{@link Iterator#hasNext hasNext} always returns {@code
+ * false}.
+ *
+ * <li>{@link Iterator#next next} always throws {@link
+ * NoSuchElementException}.
+ *
+ * <li>{@link Iterator#remove remove} always throws {@link
+ * IllegalStateException}.
+ *
+ * </ul>
+ *
+ * <p>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 <T> Iterator<T> emptyIterator() {
+ return (Iterator<T>) EmptyIterator.EMPTY_ITERATOR;
}
private static class EmptyIterator<E> implements Iterator<E> {
static final EmptyIterator<Object> EMPTY_ITERATOR
= new EmptyIterator<>();
@@ -3522,110 +4259,164 @@
private Object readResolve() {
return EMPTY_SET;
}
}
+ private static final EmptyNavigableSet<?> EMPTY_NAVIGABLE_SET =
+ new EmptyNavigableSet<>();
+
/**
* Returns the empty sorted set (immutable). This set is serializable.
*
- * <p>This example illustrates the type-safe way to obtain an empty sorted
- * set:
- * <pre>
- * SortedSet<String> s = Collections.emptySortedSet();
- * </pre>
- * Implementation note: Implementations of this method need not
- * create a separate <tt>SortedSet</tt> object for each call.
+ * <p>This example illustrates the type-safe way to obtain an empty
+ * sorted set:
+ * <pre> {@code
+ * SortedSet<String> s = Collections.emptySortedSet();
+ * }</pre>
+ *
+ * @implNote Implementations of this method need not create a separate
+ * {@code SortedSet} object for each call.
+ *
+ * @since 1.8
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> SortedSet<E> emptySortedSet() {
+ return (SortedSet<E>) EMPTY_NAVIGABLE_SET;
+ }
+
+ /**
+ * Returns the empty navigable set (immutable). This set is serializable.
+ *
+ * <p>This example illustrates the type-safe way to obtain an empty
+ * navigable set:
+ * <pre> {@code
+ * NavigableSet<String> s = Collections.emptyNavigableSet();
+ * }</pre>
+ *
+ * @implNote Implementations of this method need not
+ * create a separate {@code NavigableSet} object for each call.
*
* @since 1.8
*/
@SuppressWarnings("unchecked")
- public static final <E> SortedSet<E> emptySortedSet() {
- return (SortedSet<E>) new EmptySortedSet<>();
+ public static <E>NavigableSet<E> emptyNavigableSet() {
+ return (NavigableSet<E>) EMPTY_NAVIGABLE_SET;
}
/**
* @serial include
*/
- private static class EmptySortedSet<E>
- extends AbstractSet<E>
- implements SortedSet<E>, Serializable
+ private static class EmptyNavigableSet<E>
+ extends EmptySet<E>
+ implements NavigableSet<E>, Serializable
{
- private static final long serialVersionUID = 6316515401502265487L;
- public Iterator<E> 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> E[] toArray(E[] a) {
- if (a.length > 0)
- a[0] = null;
- return a;
+ public boolean contains(Object obj) {
+ Comparable<E> e = (Comparable<E>) obj;
+ return obj != e;
}
// Preserves singleton property
private Object readResolve() {
- return new EmptySortedSet<>();
+ return Collections.emptyNavigableSet();
}
@Override
public Comparator<? super E> comparator() {
return null;
}
@Override
@SuppressWarnings("unchecked")
- public SortedSet<E> subSet(Object fromElement, Object toElement) {
- Objects.requireNonNull(fromElement);
- Objects.requireNonNull(toElement);
+ public SortedSet<E> subSet(E fromElement, E toElement) {
+ return subSet(fromElement, true, toElement, false);
+ }
- if (!(fromElement instanceof Comparable) ||
- !(toElement instanceof Comparable))
- {
- throw new ClassCastException();
+ @Override
+ public SortedSet<E> headSet(E toElement) {
+ return headSet(toElement, false);
}
- if ((((Comparable)fromElement).compareTo(toElement) >= 0) ||
- (((Comparable)toElement).compareTo(fromElement) < 0))
- {
- throw new IllegalArgumentException();
+ @Override
+ public SortedSet<E> tailSet(E fromElement) {
+ return tailSet(fromElement, true);
}
- return emptySortedSet();
+ @Override
+ public E first() {
+ throw new NoSuchElementException();
}
@Override
- public SortedSet<E> 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<E> 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<E> descendingSet() {
+ return new BoundedEmptyNavigableSet(null, true, null, true, true);
+ }
+
+ @Override
+ public Iterator<E> descendingIterator() { return emptyIterator(); }
+
+ @Override
+ public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return new BoundedEmptyNavigableSet(
+ (Comparable<E>) Objects.requireNonNull(fromElement), fromInclusive,
+ (Comparable<E>) Objects.requireNonNull(toElement), toInclusive,
+ false);
+ }
+
+ @Override
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return new BoundedEmptyNavigableSet(
+ null, true,
+ (Comparable<E>) Objects.requireNonNull(toElement), inclusive,
+ false);
+ }
+
+ @Override
+ public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+ return new BoundedEmptyNavigableSet(
+ (Comparable<E>) Objects.requireNonNull(fromElement), inclusive,
+ null, true, false);
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> action) {
@@ -3736,10 +4527,274 @@
private Object readResolve() {
return EMPTY_LIST;
}
}
+ private static class BoundedEmptyNavigableSet<E> extends EmptyNavigableSet<E>
+ implements Serializable {
+
+ final boolean descending;
+ final boolean lowerInclusive;
+ final boolean upperInclusive;
+ final Comparable<E> lowerBound;
+ final Comparable<E> upperBound;
+
+ public BoundedEmptyNavigableSet(
+ Comparable<E> fromElement, boolean lowerInclusive,
+ Comparable<E> 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<E> comparator() {
+ return descending ? Collections.reverseOrder() : null;
+ }
+
+ public NavigableSet<E> descendingSet() {
+ return new BoundedEmptyNavigableSet(upperBound, upperInclusive, lowerBound, lowerInclusive, !descending);
+ }
+
+ @Override
+ public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return new BoundedEmptyNavigableSet(inBounds(fromElement), fromInclusive, inBounds(toElement), toInclusive, descending);
+ }
+
+ @Override
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return new BoundedEmptyNavigableSet(lowerBound, lowerInclusive, inBounds(toElement), inclusive, descending);
+ }
+
+ @Override
+ public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+ return new BoundedEmptyNavigableSet(inBounds(fromElement), inclusive, upperBound, upperInclusive, descending);
+ }
+
+ private Comparable<E> 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<E>)Objects.requireNonNull(element);
+ }
+ }
+
+private static class BoundedEmptyNavigableMap<K,V> extends EmptyNavigableMap<K,V>
+ implements Serializable {
+
+ final boolean descending;
+ final boolean lowerInclusive;
+ final boolean upperInclusive;
+ final Comparable<K> lowerBound;
+ final Comparable<K> upperBound;
+
+ public BoundedEmptyNavigableMap(
+ Comparable<K> fromElement, boolean lowerInclusive,
+ Comparable<K> 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<? super K> comparator() {
+ return descending ? Collections.reverseOrder() : null;
+ }
+
+ @Override
+ public boolean containsKey(Object obj) {
+ Comparable<K> e = (Comparable<K>) obj;
+ return obj != e;
+ }
+
+ private Comparable<K> 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<K>)Objects.requireNonNull(element);
+ }
+
+ @Override
+ public NavigableMap<K, V> descendingMap() {
+ if (upperBound == null && lowerBound == null && descending) {
+ return Collections.emptyNavigableMap();
+ }
+ return new BoundedEmptyNavigableMap(upperBound, upperInclusive, lowerBound, lowerInclusive, !descending);
+ }
+
+ @Override
+ public NavigableSet<K> navigableKeySet() {
+ if (upperBound == null && lowerBound == null && !descending) {
+ return Collections.emptyNavigableSet();
+ }
+ return new BoundedEmptyNavigableSet(lowerBound, lowerInclusive, upperBound, upperInclusive, descending);
+ }
+
+ @Override
+ public NavigableSet<K> descendingKeySet() {
+ if (upperBound == null && lowerBound == null && descending) {
+ return Collections.emptyNavigableSet();
+ }
+ return new BoundedEmptyNavigableSet(upperBound, upperInclusive, lowerBound, lowerInclusive, !descending);
+ }
+
+ @Override
+ public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return new BoundedEmptyNavigableMap(inBounds(fromKey), fromInclusive, inBounds(toKey), toInclusive, descending);
+ }
+
+ @Override
+ public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+ return new BoundedEmptyNavigableMap(lowerBound, lowerInclusive, inBounds(toKey), inclusive, descending);
+ }
+
+ @Override
+ public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+ return new BoundedEmptyNavigableMap(inBounds(fromKey), inclusive, upperBound, upperInclusive, descending);
+ }
+ }
+
/**
* The empty map (immutable). This map is serializable.
*
* @see #emptyMap()
* @since 1.3
@@ -3748,11 +4803,11 @@
public static final Map EMPTY_MAP = new EmptyMap<>();
/**
* Returns the empty map (immutable). This map is serializable.
*
- * <p>This example illustrates the type-safe way to obtain an empty set:
+ * <p>This example illustrates the type-safe way to obtain an empty map:
* <pre>
* Map<String, Date> s = Collections.emptyMap();
* </pre>
* Implementation note: Implementations of this method need not
* create a separate <tt>Map</tt> object for each call. Using this
@@ -3766,10 +4821,50 @@
public static final <K,V> Map<K,V> emptyMap() {
return (Map<K,V>) EMPTY_MAP;
}
/**
+ * Returns the empty sorted map (immutable). This map is serializable.
+ *
+ * <p>This example illustrates the type-safe way to obtain an empty map:
+ * <pre> {@code
+ * SortedMap<String, Date> s = Collections.emptySortedMap();
+ * }</pre>
+ *
+ * @implNote Implementations of this method need not create a separate
+ * {@code SortedMap} object for each call.
+ *
+ * @since 1.8
+ */
+ @SuppressWarnings("unchecked")
+ public static final <K,V> SortedMap<K,V> emptySortedMap() {
+ return (SortedMap<K,V>) EMPTY_NAVIGABLE_MAP;
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static final NavigableMap EMPTY_NAVIGABLE_MAP =
+ new EmptyNavigableMap();
+
+ /**
+ * Returns the empty navigable map (immutable). This map is serializable.
+ *
+ * <p>This example illustrates the type-safe way to obtain an empty map:
+ * <pre> {@code
+ * NavigableMap<String, Date> s = Collections.emptyNavigableMap();
+ * }</pre>
+ *
+ * @implNote Implementations of this method need not create a separate
+ * {@code NavigableMap} object for each call.
+ *
+ * @since 1.8
+ */
+ @SuppressWarnings("unchecked")
+ public static final <K,V> NavigableMap<K,V> emptyNavigableMap() {
+ return (NavigableMap<K,V>) EMPTY_NAVIGABLE_MAP;
+ }
+
+ /**
* @serial include
*/
private static class EmptyMap<K,V>
extends AbstractMap<K,V>
implements Serializable
@@ -3856,10 +4951,143 @@
private Object readResolve() {
return EMPTY_MAP;
}
}
+ private static class EmptyNavigableMap<K,V> extends EmptyMap<K,V>
+ implements NavigableMap<K,V>, Serializable {
+
+ EmptyNavigableMap() {
+
+ }
+
+ // Preserves singleton property
+ private Object readResolve() {
+ return Collections.emptyNavigableMap();
+ }
+
+ @Override
+ public Entry<K, V> lowerEntry(K key) {
+ return null;
+ }
+
+ @Override
+ public K lowerKey(K key) {
+ return null;
+ }
+
+ @Override
+ public Entry<K, V> floorEntry(K key) {
+ return null;
+ }
+
+ @Override
+ public K floorKey(K key) {
+ return null;
+ }
+
+ @Override
+ public Entry<K, V> ceilingEntry(K key) {
+ return null;
+ }
+
+ @Override
+ public K ceilingKey(K key) {
+ return null;
+ }
+
+ @Override
+ public Entry<K, V> higherEntry(K key) {
+ return null;
+ }
+
+ @Override
+ public K higherKey(K key) {
+ return null;
+ }
+
+ @Override
+ public Entry<K, V> firstEntry() {
+ return null;
+ }
+
+ @Override
+ public Entry<K, V> lastEntry() {
+ return null;
+ }
+
+ @Override
+ public Entry<K, V> pollFirstEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Entry<K, V> pollLastEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public NavigableMap<K, V> descendingMap() {
+ return new BoundedEmptyNavigableMap<>(null, true, null, true, true);
+ }
+
+ @Override
+ public NavigableSet<K> navigableKeySet() {
+ return Collections.emptyNavigableSet();
+ }
+
+ @Override
+ public NavigableSet<K> descendingKeySet() {
+ return Collections.<K>emptyNavigableSet().descendingSet();
+ }
+
+ @Override
+ public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+ return new BoundedEmptyNavigableMap<>((Comparable<K>) fromKey, fromInclusive, (Comparable<K>) toKey, toInclusive, false);
+ }
+
+ @Override
+ public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+ return new BoundedEmptyNavigableMap<>(null, false, (Comparable<K>) toKey, inclusive, false);
+ }
+
+ @Override
+ public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+ return new BoundedEmptyNavigableMap<>((Comparable<K>) fromKey, inclusive, null, false, false);
+ }
+
+ @Override
+ public SortedMap<K, V> subMap(K fromKey, K toKey) {
+ return subMap(fromKey, true, toKey, false);
+ }
+
+ @Override
+ public SortedMap<K, V> headMap(K toKey) {
+ return headMap(toKey, false);
+ }
+
+ @Override
+ public SortedMap<K, V> tailMap(K fromKey) {
+ return tailMap(fromKey, true);
+ }
+
+ @Override
+ public Comparator<? super K> comparator() {
+ return null;
+ }
+
+ @Override
+ public K firstKey() {
+ return null;
+ }
+
+ @Override
+ public K lastKey() {
+ return null;
+ }
+ }
+
// Singleton collections
/**
* Returns an immutable set containing only the specified object.
* The returned set is serializable.