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,1219 **** --- 1210,1283 ---- 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,1677 **** --- 1732,1866 ---- 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,1952 **** --- 2132,2245 ---- 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,2454 **** 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. * ! * <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") --- 2675,2925 ---- public K lastKey() { synchronized (mutex) {return sm.lastKey();} } } /** ! * 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> * ! * 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>The returned navigable map will be serializable if the specified ! * navigable map is serializable. * ! * @param m the navigable map to be "wrapped" in a synchronized navigable ! * map ! * @return a synchronized view of the specified navigable map. ! * @since 1.8 */ ! public static <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,2735 **** --- 3197,3308 ---- 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,3359 **** 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}. * ! * <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<>(); --- 3896,4096 ---- public SortedMap<K,V> tailMap(K fromKey) { return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType); } } /** ! * 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. * ! * <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. * ! * <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 map will be serializable if the specified map is ! * serializable. * ! * <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. * ! * @param m the map for which a dynamically typesafe view is to be ! * returned ! * @param keyType the type of key that {@code m} is permitted to hold ! * @param valueType the type of value that {@code m} is permitted to hold ! * @return a dynamically typesafe view of the specified map ! * @since 1.8 */ ! public static <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,3631 **** private Object readResolve() { return EMPTY_SET; } } /** * 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&lt;String&gt; s = Collections.emptySortedSet(); ! * </pre> ! * Implementation note: Implementations of this method need not ! * create a separate <tt>SortedSet</tt> object for each call. * * @since 1.8 */ @SuppressWarnings("unchecked") ! public static final <E> SortedSet<E> emptySortedSet() { ! return (SortedSet<E>) new EmptySortedSet<>(); } /** * @serial include */ ! private static class EmptySortedSet<E> ! extends AbstractSet<E> ! implements SortedSet<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]; } ! public <E> E[] toArray(E[] a) { ! if (a.length > 0) ! a[0] = null; ! return a; } // Preserves singleton property private Object readResolve() { ! return new EmptySortedSet<>(); } @Override public Comparator<? super E> comparator() { return null; } @Override @SuppressWarnings("unchecked") ! public SortedSet<E> subSet(Object fromElement, Object toElement) { ! Objects.requireNonNull(fromElement); ! Objects.requireNonNull(toElement); ! if (!(fromElement instanceof Comparable) || ! !(toElement instanceof Comparable)) ! { ! throw new ClassCastException(); } ! if ((((Comparable)fromElement).compareTo(toElement) >= 0) || ! (((Comparable)toElement).compareTo(fromElement) < 0)) ! { ! throw new IllegalArgumentException(); } ! return emptySortedSet(); } @Override ! public SortedSet<E> headSet(Object toElement) { ! Objects.requireNonNull(toElement); ! if (!(toElement instanceof Comparable)) { ! throw new ClassCastException(); } ! return emptySortedSet(); } @Override ! public SortedSet<E> tailSet(Object fromElement) { ! Objects.requireNonNull(fromElement); ! if (!(fromElement instanceof Comparable)) { ! throw new ClassCastException(); } ! return emptySortedSet(); } @Override ! public E first() { ! throw new NoSuchElementException(); } @Override ! public E last() { ! throw new NoSuchElementException(); } // Override default methods in Collection @Override public void forEach(Consumer<? super E> action) { --- 4259,4422 ---- 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> {@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 <E>NavigableSet<E> emptyNavigableSet() { ! return (NavigableSet<E>) EMPTY_NAVIGABLE_SET; } /** * @serial include */ ! private static class EmptyNavigableSet<E> ! extends EmptySet<E> ! implements NavigableSet<E>, Serializable { ! // private static final long serialVersionUID = 6316515401502265487L; ! public boolean contains(Object obj) { ! Comparable<E> e = (Comparable<E>) obj; ! return obj != e; } // Preserves singleton property private Object readResolve() { ! return Collections.emptyNavigableSet(); } @Override public Comparator<? super E> comparator() { return null; } @Override @SuppressWarnings("unchecked") ! public SortedSet<E> subSet(E fromElement, E toElement) { ! return subSet(fromElement, true, toElement, false); ! } ! @Override ! public SortedSet<E> headSet(E toElement) { ! return headSet(toElement, false); } ! @Override ! public SortedSet<E> tailSet(E fromElement) { ! return tailSet(fromElement, true); } ! @Override ! public E first() { ! throw new NoSuchElementException(); } @Override ! public E last() { ! throw new NoSuchElementException(); ! } ! @Override ! public E lower(E e) { ! Objects.requireNonNull(e); ! return null; } ! @Override ! public E floor(E e) { ! Objects.requireNonNull(e); ! return null; } @Override ! public E ceiling(E e) { ! Objects.requireNonNull(e); ! return null; ! } ! @Override ! public E higher(E e) { ! Objects.requireNonNull(e); ! return null; } ! @Override ! public E pollFirst() { ! return null; } @Override ! public E pollLast() { ! return null; } @Override ! 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,3745 **** --- 4527,4800 ---- 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,3758 **** 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: * <pre> * Map&lt;String, Date&gt; s = Collections.emptyMap(); * </pre> * Implementation note: Implementations of this method need not * create a separate <tt>Map</tt> object for each call. Using this --- 4803,4813 ---- 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 map: * <pre> * Map&lt;String, Date&gt; 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,3775 **** --- 4821,4870 ---- 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,3865 **** --- 4951,5093 ---- 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.