92aaa24628
From-SVN: r49104
3475 lines
87 KiB
Java
3475 lines
87 KiB
Java
/* Collections.java -- Utility class with methods to operate on collections
|
||
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||
|
||
This file is part of GNU Classpath.
|
||
|
||
GNU Classpath is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2, or (at your option)
|
||
any later version.
|
||
|
||
GNU Classpath is distributed in the hope that it will be useful, but
|
||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||
02111-1307 USA.
|
||
|
||
Linking this library statically or dynamically with other modules is
|
||
making a combined work based on this library. Thus, the terms and
|
||
conditions of the GNU General Public License cover the whole
|
||
combination.
|
||
|
||
As a special exception, the copyright holders of this library give you
|
||
permission to link this library with independent modules to produce an
|
||
executable, regardless of the license terms of these independent
|
||
modules, and to copy and distribute the resulting executable under
|
||
terms of your choice, provided that you also meet, for each linked
|
||
independent module, the terms and conditions of the license of that
|
||
module. An independent module is a module which is not derived from
|
||
or based on this library. If you modify this library, you may extend
|
||
this exception to your version of the library, but you are not
|
||
obligated to do so. If you do not wish to do so, delete this
|
||
exception statement from your version. */
|
||
|
||
|
||
package java.util;
|
||
|
||
import java.io.Serializable;
|
||
|
||
/**
|
||
* Utility class consisting of static methods that operate on, or return
|
||
* Collections. Contains methods to sort, search, reverse, fill and shuffle
|
||
* Collections, methods to facilitate interoperability with legacy APIs that
|
||
* are unaware of collections, a method to return a list which consists of
|
||
* multiple copies of one element, and methods which "wrap" collections to give
|
||
* them extra properties, such as thread-safety and unmodifiability.
|
||
* <p>
|
||
*
|
||
* All methods which take a collection throw a {@link NullPointerException} if
|
||
* that collection is null. Algorithms which can change a collection may, but
|
||
* are not required, to throw the {@link UnsupportedOperationException} that
|
||
* the underlying collection would throw during an attempt at modification.
|
||
* For example,
|
||
* <code>Collections.singleton("").addAll(Collections.EMPTY_SET)<code>
|
||
* does not throw a exception, even though addAll is an unsupported operation
|
||
* on a singleton; the reason for this is that addAll did not attempt to
|
||
* modify the set.
|
||
*
|
||
* @author Original author unknown
|
||
* @author Bryce McKinlay
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
* @see Collection
|
||
* @see Set
|
||
* @see List
|
||
* @see Map
|
||
* @see Arrays
|
||
* @since 1.2
|
||
* @status updated to 1.4
|
||
*/
|
||
public class Collections
|
||
{
|
||
/**
|
||
* Constant used to decide cutoff for when a non-RandomAccess list should
|
||
* be treated as sequential-access. Basically, quadratic behavior is
|
||
* acceptible for small lists when the overhead is so small in the first
|
||
* place. I arbitrarily set it to 16, so it may need some tuning.
|
||
*/
|
||
private static final int LARGE_LIST_SIZE = 16;
|
||
|
||
/**
|
||
* Determines if a list should be treated as a sequential-access one.
|
||
* Rather than the old method of JDK 1.3 of assuming only instanceof
|
||
* AbstractSequentialList should be sequential, this uses the new method
|
||
* of JDK 1.4 of assuming anything that does NOT implement RandomAccess
|
||
* and exceeds a large (unspecified) size should be sequential.
|
||
*
|
||
* @param l the list to check
|
||
* @return true if it should be treated as sequential-access
|
||
*/
|
||
private static boolean isSequential(List l)
|
||
{
|
||
return ! (l instanceof RandomAccess) && l.size() > LARGE_LIST_SIZE;
|
||
}
|
||
|
||
/**
|
||
* This class is non-instantiable.
|
||
*/
|
||
private Collections()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* An immutable, serializable, empty Set.
|
||
* @see Serializable
|
||
*/
|
||
public static final Set EMPTY_SET = new EmptySet();
|
||
|
||
private static final Iterator EMPTY_ITERATOR = new Iterator()
|
||
{
|
||
public boolean hasNext()
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public Object next()
|
||
{
|
||
throw new NoSuchElementException();
|
||
}
|
||
|
||
public void remove()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* The implementation of {@link #EMPTY_SET}. This class name is required
|
||
* for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class EmptySet extends AbstractSet
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1582296315990362920L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
EmptySet()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* The size: always 0!
|
||
*/
|
||
public int size()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Returns an iterator that does not iterate.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
return EMPTY_ITERATOR;
|
||
}
|
||
} // class EmptySet
|
||
|
||
/**
|
||
* An immutable, serializable, empty List, which implements RandomAccess.
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static final List EMPTY_LIST = new EmptyList();
|
||
|
||
/**
|
||
* The implementation of {@link #EMPTY_LIST}. This class name is required
|
||
* for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class EmptyList extends AbstractList
|
||
implements Serializable, RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 8842843931221139166L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
EmptyList()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* The size is always 0.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* No matter the index, it is out of bounds.
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
/**
|
||
* Returns an iterator that does not iterate. Optional, but avoids
|
||
* allocation of an iterator in AbstractList.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
return EMPTY_ITERATOR;
|
||
}
|
||
} // class EmptyList
|
||
|
||
/**
|
||
* An immutable, serializable, empty Map.
|
||
* @see Serializable
|
||
*/
|
||
public static final Map EMPTY_MAP = new EmptyMap();
|
||
|
||
/**
|
||
* The implementation of {@link #EMPTY_MAP}. This class name is required
|
||
* for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class EmptyMap extends AbstractMap
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 6428348081105594320L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
EmptyMap()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* There are no entries.
|
||
*/
|
||
public Set entrySet()
|
||
{
|
||
return EMPTY_SET;
|
||
}
|
||
|
||
/**
|
||
* Size is always 0.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* No entries. Technically, EMPTY_SET, while more specific than a general
|
||
* Collection, will work. Besides, that's what the JDK uses!
|
||
*/
|
||
public Collection values()
|
||
{
|
||
return EMPTY_SET;
|
||
}
|
||
} // class EmptyMap
|
||
|
||
/**
|
||
* Compare two objects with or without a Comparator. If c is null, uses the
|
||
* natural ordering. Slightly slower than doing it inline if the JVM isn't
|
||
* clever, but worth it for removing a duplicate of the search code.
|
||
* Note: This code is also used in Arrays (for sort as well as search).
|
||
*/
|
||
static final int compare(Object o1, Object o2, Comparator c)
|
||
{
|
||
return c == null ? ((Comparable) o1).compareTo(o2) : c.compare(o1, o2);
|
||
}
|
||
|
||
/**
|
||
* Perform a binary search of a List for a key, using the natural ordering of
|
||
* the elements. The list must be sorted (as by the sort() method) - if it is
|
||
* not, the behavior of this method is undefined, and may be an infinite
|
||
* loop. Further, the key must be comparable with every item in the list. If
|
||
* the list contains the key more than once, any one of them may be found.
|
||
* <p>
|
||
*
|
||
* This algorithm behaves in log(n) time for {@link RandomAccess} lists,
|
||
* and uses a linear search with O(n) link traversals and log(n) comparisons
|
||
* with {@link AbstractSequentialList} lists. Note: although the
|
||
* specification allows for an infinite loop if the list is unsorted, it will
|
||
* not happen in this (Classpath) implementation.
|
||
*
|
||
* @param l the list to search (must be sorted)
|
||
* @param key the value to search for
|
||
* @return the index at which the key was found, or -n-1 if it was not
|
||
* found, where n is the index of the first value higher than key or
|
||
* a.length if there is no such value
|
||
* @throws ClassCastException if key could not be compared with one of the
|
||
* elements of l
|
||
* @throws NullPointerException if a null element has compareTo called
|
||
* @see #sort(List)
|
||
*/
|
||
public static int binarySearch(List l, Object key)
|
||
{
|
||
return binarySearch(l, key, null);
|
||
}
|
||
|
||
/**
|
||
* Perform a binary search of a List for a key, using a supplied Comparator.
|
||
* The list must be sorted (as by the sort() method with the same Comparator)
|
||
* - if it is not, the behavior of this method is undefined, and may be an
|
||
* infinite loop. Further, the key must be comparable with every item in the
|
||
* list. If the list contains the key more than once, any one of them may be
|
||
* found. If the comparator is null, the elements' natural ordering is used.
|
||
* <p>
|
||
*
|
||
* This algorithm behaves in log(n) time for {@link RandomAccess} lists,
|
||
* and uses a linear search with O(n) link traversals and log(n) comparisons
|
||
* with {@link AbstractSequentialList} lists. Note: although the
|
||
* specification allows for an infinite loop if the list is unsorted, it will
|
||
* not happen in this (Classpath) implementation.
|
||
*
|
||
* @param l the list to search (must be sorted)
|
||
* @param key the value to search for
|
||
* @param c the comparator by which the list is sorted
|
||
* @return the index at which the key was found, or -n-1 if it was not
|
||
* found, where n is the index of the first value higher than key or
|
||
* a.length if there is no such value
|
||
* @throws ClassCastException if key could not be compared with one of the
|
||
* elements of l
|
||
* @throws NullPointerException if a null element is compared with natural
|
||
* ordering (only possible when c is null)
|
||
* @see #sort(List, Comparator)
|
||
*/
|
||
public static int binarySearch(List l, Object key, Comparator c)
|
||
{
|
||
int pos = 0;
|
||
int low = 0;
|
||
int hi = l.size() - 1;
|
||
|
||
// We use a linear search with log(n) comparisons using an iterator
|
||
// if the list is sequential-access.
|
||
if (isSequential(l))
|
||
{
|
||
ListIterator itr = l.listIterator();
|
||
int i = 0;
|
||
while (low <= hi)
|
||
{
|
||
pos = (low + hi) >> 1;
|
||
if (i < pos)
|
||
for ( ; i != pos; i++, itr.next());
|
||
else
|
||
for ( ; i != pos; i--, itr.previous());
|
||
final int d = compare(key, itr.next(), c);
|
||
if (d == 0)
|
||
return pos;
|
||
else if (d < 0)
|
||
hi = pos - 1;
|
||
else
|
||
// This gets the insertion point right on the last loop
|
||
low = ++pos;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
while (low <= hi)
|
||
{
|
||
pos = (low + hi) >> 1;
|
||
final int d = compare(key, l.get(pos), c);
|
||
if (d == 0)
|
||
return pos;
|
||
else if (d < 0)
|
||
hi = pos - 1;
|
||
else
|
||
// This gets the insertion point right on the last loop
|
||
low = ++pos;
|
||
}
|
||
}
|
||
|
||
// If we failed to find it, we do the same whichever search we did.
|
||
return -pos - 1;
|
||
}
|
||
|
||
/**
|
||
* Copy one list to another. If the destination list is longer than the
|
||
* source list, the remaining elements are unaffected. This method runs in
|
||
* linear time.
|
||
*
|
||
* @param dest the destination list
|
||
* @param source the source list
|
||
* @throws IndexOutOfBoundsException if the destination list is shorter
|
||
* than the source list (the destination will be unmodified)
|
||
* @throws UnsupportedOperationException if dest.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void copy(List dest, List source)
|
||
{
|
||
int pos = source.size();
|
||
if (dest.size() < pos)
|
||
throw new IndexOutOfBoundsException("Source does not fit in dest");
|
||
|
||
Iterator i1 = source.iterator();
|
||
ListIterator i2 = dest.listIterator();
|
||
|
||
while (--pos >= 0)
|
||
{
|
||
i2.next();
|
||
i2.set(i1.next());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns an Enumeration over a collection. This allows interoperability
|
||
* with legacy APIs that require an Enumeration as input.
|
||
*
|
||
* @param c the Collection to iterate over
|
||
* @return an Enumeration backed by an Iterator over c
|
||
*/
|
||
public static Enumeration enumeration(Collection c)
|
||
{
|
||
final Iterator i = c.iterator();
|
||
return new Enumeration()
|
||
{
|
||
public final boolean hasMoreElements()
|
||
{
|
||
return i.hasNext();
|
||
}
|
||
public final Object nextElement()
|
||
{
|
||
return i.next();
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Replace every element of a list with a given value. This method runs in
|
||
* linear time.
|
||
*
|
||
* @param l the list to fill.
|
||
* @param val the object to vill the list with.
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation.
|
||
*/
|
||
public static void fill(List l, Object val)
|
||
{
|
||
ListIterator itr = l.listIterator();
|
||
for (int i = l.size() - 1; i >= 0; --i)
|
||
{
|
||
itr.next();
|
||
itr.set(val);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the starting index where the specified sublist first occurs
|
||
* in a larger list, or -1 if there is no matching position. If
|
||
* <code>target.size() > source.size()</code>, this returns -1,
|
||
* otherwise this implementation uses brute force, checking for
|
||
* <code>source.sublist(i, i + target.size()).equals(target)</code>
|
||
* for all possible i.
|
||
*
|
||
* @param source the list to search
|
||
* @param target the sublist to search for
|
||
* @return the index where found, or -1
|
||
* @since 1.4
|
||
*/
|
||
public static int indexOfSubList(List source, List target)
|
||
{
|
||
int ssize = source.size();
|
||
for (int i = 0, j = target.size(); j <= ssize; i++, j++)
|
||
if (source.subList(i, j).equals(target))
|
||
return i;
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Returns the starting index where the specified sublist last occurs
|
||
* in a larger list, or -1 if there is no matching position. If
|
||
* <code>target.size() > source.size()</code>, this returns -1,
|
||
* otherwise this implementation uses brute force, checking for
|
||
* <code>source.sublist(i, i + target.size()).equals(target)</code>
|
||
* for all possible i.
|
||
*
|
||
* @param source the list to search
|
||
* @param target the sublist to search for
|
||
* @return the index where found, or -1
|
||
* @since 1.4
|
||
*/
|
||
public static int lastIndexOfSubList(List source, List target)
|
||
{
|
||
int ssize = source.size();
|
||
for (int i = ssize - target.size(), j = ssize; i >= 0; i--, j--)
|
||
if (source.subList(i, j).equals(target))
|
||
return i;
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Returns an array list holding the elements visited by a given
|
||
* Enumeration. This method exists for interoperability between legacy
|
||
* APIs and the new Collection API.
|
||
*
|
||
* @param e the enumeration to put in a list
|
||
* @return a list containing the enumeration elements
|
||
* @see ArrayList
|
||
* @since 1.4
|
||
*/
|
||
public static List list(Enumeration e)
|
||
{
|
||
List l = new ArrayList();
|
||
while (e.hasMoreElements())
|
||
l.add(e.nextElement());
|
||
return l;
|
||
}
|
||
|
||
/**
|
||
* Find the maximum element in a Collection, according to the natural
|
||
* ordering of the elements. This implementation iterates over the
|
||
* Collection, so it works in linear time.
|
||
*
|
||
* @param c the Collection to find the maximum element of
|
||
* @return the maximum element of c
|
||
* @exception NoSuchElementException if c is empty
|
||
* @exception ClassCastException if elements in c are not mutually comparable
|
||
* @exception NullPointerException if null.compareTo is called
|
||
*/
|
||
public static Object max(Collection c)
|
||
{
|
||
return max(c, null);
|
||
}
|
||
|
||
/**
|
||
* Find the maximum element in a Collection, according to a specified
|
||
* Comparator. This implementation iterates over the Collection, so it
|
||
* works in linear time.
|
||
*
|
||
* @param c the Collection to find the maximum element of
|
||
* @param order the Comparator to order the elements by, or null for natural
|
||
* ordering
|
||
* @return the maximum element of c
|
||
* @throws NoSuchElementException if c is empty
|
||
* @throws ClassCastException if elements in c are not mutually comparable
|
||
* @throws NullPointerException if null is compared by natural ordering
|
||
* (only possible when order is null)
|
||
*/
|
||
public static Object max(Collection c, Comparator order)
|
||
{
|
||
Iterator itr = c.iterator();
|
||
Object max = itr.next(); // throws NoSuchElementException
|
||
int csize = c.size();
|
||
for (int i = 1; i < csize; i++)
|
||
{
|
||
Object o = itr.next();
|
||
if (compare(max, o, order) < 0)
|
||
max = o;
|
||
}
|
||
return max;
|
||
}
|
||
|
||
/**
|
||
* Find the minimum element in a Collection, according to the natural
|
||
* ordering of the elements. This implementation iterates over the
|
||
* Collection, so it works in linear time.
|
||
*
|
||
* @param c the Collection to find the minimum element of
|
||
* @return the minimum element of c
|
||
* @throws NoSuchElementException if c is empty
|
||
* @throws ClassCastException if elements in c are not mutually comparable
|
||
* @throws NullPointerException if null.compareTo is called
|
||
*/
|
||
public static Object min(Collection c)
|
||
{
|
||
return min(c, null);
|
||
}
|
||
|
||
/**
|
||
* Find the minimum element in a Collection, according to a specified
|
||
* Comparator. This implementation iterates over the Collection, so it
|
||
* works in linear time.
|
||
*
|
||
* @param c the Collection to find the minimum element of
|
||
* @param order the Comparator to order the elements by, or null for natural
|
||
* ordering
|
||
* @return the minimum element of c
|
||
* @throws NoSuchElementException if c is empty
|
||
* @throws ClassCastException if elements in c are not mutually comparable
|
||
* @throws NullPointerException if null is compared by natural ordering
|
||
* (only possible when order is null)
|
||
*/
|
||
public static Object min(Collection c, Comparator order)
|
||
{
|
||
Iterator itr = c.iterator();
|
||
Object min = itr.next(); // throws NoSuchElementExcception
|
||
int csize = c.size();
|
||
for (int i = 1; i < csize; i++)
|
||
{
|
||
Object o = itr.next();
|
||
if (compare(min, o, order) > 0)
|
||
min = o;
|
||
}
|
||
return min;
|
||
}
|
||
|
||
/**
|
||
* Creates an immutable list consisting of the same object repeated n times.
|
||
* The returned object is tiny, consisting of only a single reference to the
|
||
* object and a count of the number of elements. It is Serializable, and
|
||
* implements RandomAccess. You can use it in tandem with List.addAll for
|
||
* fast list construction.
|
||
*
|
||
* @param n the number of times to repeat the object
|
||
* @param o the object to repeat
|
||
* @return a List consisting of n copies of o
|
||
* @throws IllegalArgumentException if n < 0
|
||
* @see List#addAll(Collection)
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static List nCopies(final int n, final Object o)
|
||
{
|
||
return new CopiesList(n, o);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #nCopies(int, Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class CopiesList extends AbstractList
|
||
implements Serializable, RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 2739099268398711800L;
|
||
|
||
/**
|
||
* The count of elements in this list.
|
||
* @serial the list size
|
||
*/
|
||
private final int n;
|
||
|
||
/**
|
||
* The repeated list element.
|
||
* @serial the list contents
|
||
*/
|
||
private final Object element;
|
||
|
||
/**
|
||
* Constructs the list.
|
||
*
|
||
* @param n the count
|
||
* @param o the object
|
||
* @throws IllegalArgumentException if n < 0
|
||
*/
|
||
CopiesList(int n, Object o)
|
||
{
|
||
if (n < 0)
|
||
throw new IllegalArgumentException();
|
||
this.n = n;
|
||
element = o;
|
||
}
|
||
|
||
/**
|
||
* The size is fixed.
|
||
*/
|
||
public int size()
|
||
{
|
||
return n;
|
||
}
|
||
|
||
/**
|
||
* The same element is returned.
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
if (index < 0 || index >= n)
|
||
throw new IndexOutOfBoundsException();
|
||
return element;
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractList.
|
||
/**
|
||
* This list only contains one element.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return n > 0 && equals(o, element);
|
||
}
|
||
|
||
/**
|
||
* The index is either 0 or -1.
|
||
*/
|
||
public int indexOf(Object o)
|
||
{
|
||
return (n > 0 && equals(o, element)) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* The index is either n-1 or -1.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return equals(o, element) ? n - 1 : -1;
|
||
}
|
||
|
||
/**
|
||
* A subList is just another CopiesList.
|
||
*/
|
||
public List subList(int from, int to)
|
||
{
|
||
if (from < 0 || to > n)
|
||
throw new IndexOutOfBoundsException();
|
||
return new CopiesList(to - from, element);
|
||
}
|
||
|
||
/**
|
||
* The array is easy.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
Object[] a = new Object[n];
|
||
Arrays.fill(a, element);
|
||
return a;
|
||
}
|
||
|
||
/**
|
||
* The string is easy to generate.
|
||
*/
|
||
public String toString()
|
||
{
|
||
StringBuffer r = new StringBuffer("{");
|
||
for (int i = n - 1; --i > 0; )
|
||
r.append(element).append(", ");
|
||
r.append(element).append("}");
|
||
return r.toString();
|
||
}
|
||
} // class CopiesList
|
||
|
||
/**
|
||
* Replace all instances of one object with another in the specified list.
|
||
* The list does not change size. An element e is replaced if
|
||
* <code>oldval == null ? e == null : oldval.equals(e)</code>.
|
||
*
|
||
* @param list the list to iterate over
|
||
* @param oldval the element to replace
|
||
* @param newval the new value for the element
|
||
* @return true if a replacement occurred
|
||
* @throws UnsupportedOperationException if the list iterator does not allow
|
||
* for the set operation
|
||
* @throws ClassCastException newval is of a type which cannot be added
|
||
* to the list
|
||
* @throws IllegalArgumentException some other aspect of newval stops
|
||
* it being added to the list
|
||
* @since 1.4
|
||
*/
|
||
public static boolean replaceAll(List list, Object oldval, Object newval)
|
||
{
|
||
ListIterator itr = list.listIterator();
|
||
boolean replace_occured = false;
|
||
for (int i = list.size(); --i >= 0; )
|
||
if (AbstractCollection.equals(oldval, itr.next()))
|
||
{
|
||
itr.set(newval);
|
||
replace_occured = true;
|
||
}
|
||
return replace_occured;
|
||
}
|
||
|
||
/**
|
||
* Reverse a given list. This method works in linear time.
|
||
*
|
||
* @param l the list to reverse
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void reverse(List l)
|
||
{
|
||
ListIterator i1 = l.listIterator();
|
||
int pos1 = 1;
|
||
int pos2 = l.size();
|
||
ListIterator i2 = l.listIterator(pos2);
|
||
while (pos1 < pos2)
|
||
{
|
||
Object o = i1.next();
|
||
i1.set(i2.previous());
|
||
i2.set(o);
|
||
++pos1;
|
||
--pos2;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get a comparator that implements the reverse of natural ordering. In
|
||
* other words, this sorts Comparable objects opposite of how their
|
||
* compareTo method would sort. This makes it easy to sort into reverse
|
||
* order, by simply passing Collections.reverseOrder() to the sort method.
|
||
* The return value of this method is Serializable.
|
||
*
|
||
* @return a comparator that imposes reverse natural ordering
|
||
* @see Comparable
|
||
* @see Serializable
|
||
*/
|
||
public static Comparator reverseOrder()
|
||
{
|
||
return rcInstance;
|
||
}
|
||
|
||
/**
|
||
* The object for {@link #reverseOrder()}.
|
||
*/
|
||
static private final ReverseComparator rcInstance = new ReverseComparator();
|
||
|
||
/**
|
||
* The implementation of {@link #reverseOrder()}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class ReverseComparator
|
||
implements Comparator, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
static private final long serialVersionUID = 7207038068494060240L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
ReverseComparator()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* Compare two objects in reverse natural order.
|
||
*
|
||
* @param a the first object
|
||
* @param b the second object
|
||
* @return <, ==, or > 0 according to b.compareTo(a)
|
||
*/
|
||
public int compare(Object a, Object b)
|
||
{
|
||
return ((Comparable) b).compareTo(a);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Rotate the elements in a list by a specified distance. After calling this
|
||
* method, the element now at index <code>i</code> was formerly at index
|
||
* <code>(i - distance) mod list.size()</code>. The list size is unchanged.
|
||
* <p>
|
||
*
|
||
* For example, suppose a list contains <code>[t, a, n, k, s]</code>. After
|
||
* either <code>Collections.rotate(l, 4)</code> or
|
||
* <code>Collections.rotate(l, -1)</code>, the new contents are
|
||
* <code>[s, t, a, n, k]</code>. This can be applied to sublists to rotate
|
||
* just a portion of the list. For example, to move element <code>a</code>
|
||
* forward two positions in the original example, use
|
||
* <code>Collections.rotate(l.subList(1, 3+1), -1)</code>, which will
|
||
* result in <code>[t, n, k, a, s]</code>.
|
||
* <p>
|
||
*
|
||
* If the list is small or implements {@link RandomAccess}, the
|
||
* implementation exchanges the first element to its destination, then the
|
||
* displaced element, and so on until a circuit has been completed. The
|
||
* process is repeated if needed on the second element, and so forth, until
|
||
* all elements have been swapped. For large non-random lists, the
|
||
* implementation breaks the list into two sublists at index
|
||
* <code>-distance mod size</code>, calls {@link #reverse(List)} on the
|
||
* pieces, then reverses the overall list.
|
||
*
|
||
* @param list the list to rotate
|
||
* @param distance the distance to rotate by; unrestricted in value
|
||
* @throws UnsupportedOperationException if the list does not support set
|
||
* @since 1.4
|
||
*/
|
||
public static void rotate(List list, int distance)
|
||
{
|
||
int size = list.size();
|
||
distance %= size;
|
||
if (distance == 0)
|
||
return;
|
||
if (distance < 0)
|
||
distance += size;
|
||
|
||
if (isSequential(list))
|
||
{
|
||
reverse(list);
|
||
reverse(list.subList(0, distance));
|
||
reverse(list.subList(distance, size));
|
||
}
|
||
else
|
||
{
|
||
// Determine the least common multiple of distance and size, as there
|
||
// are (distance / LCM) loops to cycle through.
|
||
int a = size;
|
||
int lcm = distance;
|
||
int b = a % lcm;
|
||
while (b != 0)
|
||
{
|
||
a = lcm;
|
||
lcm = b;
|
||
b = a % lcm;
|
||
}
|
||
|
||
// Now, make the swaps. We must take the remainder every time through
|
||
// the inner loop so that we don't overflow i to negative values.
|
||
while (--lcm >= 0)
|
||
{
|
||
Object o = list.get(lcm);
|
||
for (int i = lcm + distance; i != lcm; i = (i + distance) % size)
|
||
o = list.set(i, o);
|
||
list.set(lcm, o);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Shuffle a list according to a default source of randomness. The algorithm
|
||
* used iterates backwards over the list, swapping each element with an
|
||
* element randomly selected from the elements in positions less than or
|
||
* equal to it (using r.nextInt(int)).
|
||
* <p>
|
||
*
|
||
* This algorithm would result in a perfectly fair shuffle (that is, each
|
||
* element would have an equal chance of ending up in any position) if r were
|
||
* a perfect source of randomness. In practice the results are merely very
|
||
* close to perfect.
|
||
* <p>
|
||
*
|
||
* This method operates in linear time. To do this on large lists which do
|
||
* not implement {@link RandomAccess}, a temporary array is used to acheive
|
||
* this speed, since it would be quadratic access otherwise.
|
||
*
|
||
* @param l the list to shuffle
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void shuffle(List l)
|
||
{
|
||
if (defaultRandom == null)
|
||
{
|
||
synchronized (Collections.class)
|
||
{
|
||
if (defaultRandom == null)
|
||
defaultRandom = new Random();
|
||
}
|
||
}
|
||
shuffle(l, defaultRandom);
|
||
}
|
||
|
||
/**
|
||
* Cache a single Random object for use by shuffle(List). This improves
|
||
* performance as well as ensuring that sequential calls to shuffle() will
|
||
* not result in the same shuffle order occurring: the resolution of
|
||
* System.currentTimeMillis() is not sufficient to guarantee a unique seed.
|
||
*/
|
||
private static Random defaultRandom = null;
|
||
|
||
/**
|
||
* Shuffle a list according to a given source of randomness. The algorithm
|
||
* used iterates backwards over the list, swapping each element with an
|
||
* element randomly selected from the elements in positions less than or
|
||
* equal to it (using r.nextInt(int)).
|
||
* <p>
|
||
*
|
||
* This algorithm would result in a perfectly fair shuffle (that is, each
|
||
* element would have an equal chance of ending up in any position) if r were
|
||
* a perfect source of randomness. In practise (eg if r = new Random()) the
|
||
* results are merely very close to perfect.
|
||
* <p>
|
||
*
|
||
* This method operates in linear time. To do this on large lists which do
|
||
* not implement {@link RandomAccess}, a temporary array is used to acheive
|
||
* this speed, since it would be quadratic access otherwise.
|
||
*
|
||
* @param l the list to shuffle
|
||
* @param r the source of randomness to use for the shuffle
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void shuffle(List l, Random r)
|
||
{
|
||
int lsize = l.size();
|
||
ListIterator i = l.listIterator(lsize);
|
||
boolean sequential = isSequential(l);
|
||
Object[] a = null; // stores a copy of the list for the sequential case
|
||
|
||
if (sequential)
|
||
a = l.toArray();
|
||
|
||
for (int pos = lsize - 1; pos > 0; --pos)
|
||
{
|
||
// Obtain a random position to swap with. pos + 1 is used so that the
|
||
// range of the random number includes the current position.
|
||
int swap = r.nextInt(pos + 1);
|
||
|
||
// Swap the desired element.
|
||
Object o;
|
||
if (sequential)
|
||
{
|
||
o = a[swap];
|
||
a[swap] = i.previous();
|
||
}
|
||
else
|
||
o = l.set(swap, i.previous());
|
||
|
||
i.set(o);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Obtain an immutable Set consisting of a single element. The return value
|
||
* of this method is Serializable.
|
||
*
|
||
* @param o the single element
|
||
* @return an immutable Set containing only o
|
||
* @see Serializable
|
||
*/
|
||
public static Set singleton(Object o)
|
||
{
|
||
return new SingletonSet(o);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #singleton(Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SingletonSet extends AbstractSet
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 3193687207550431679L;
|
||
|
||
|
||
/**
|
||
* The single element; package visible for use in nested class.
|
||
* @serial the singleton
|
||
*/
|
||
final Object element;
|
||
|
||
/**
|
||
* Construct a singleton.
|
||
* @param o the element
|
||
*/
|
||
SingletonSet(Object o)
|
||
{
|
||
element = o;
|
||
}
|
||
|
||
/**
|
||
* The size: always 1!
|
||
*/
|
||
public int size()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Returns an iterator over the lone element.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
return new Iterator()
|
||
{
|
||
private boolean hasNext = true;
|
||
|
||
public boolean hasNext()
|
||
{
|
||
return hasNext;
|
||
}
|
||
|
||
public Object next()
|
||
{
|
||
if (hasNext)
|
||
{
|
||
hasNext = false;
|
||
return element;
|
||
}
|
||
else
|
||
throw new NoSuchElementException();
|
||
}
|
||
|
||
public void remove()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
};
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractSet.
|
||
/**
|
||
* The set only contains one element.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return equals(o, element);
|
||
}
|
||
|
||
/**
|
||
* This is true if the other collection only contains the element.
|
||
*/
|
||
public boolean containsAll(Collection c)
|
||
{
|
||
Iterator i = c.iterator();
|
||
int pos = c.size();
|
||
while (--pos >= 0)
|
||
if (! equals(i.next(), element))
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* The hash is just that of the element.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return hashCode(element);
|
||
}
|
||
|
||
/**
|
||
* Returning an array is simple.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return new Object[] {element};
|
||
}
|
||
|
||
/**
|
||
* Obvious string.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[" + element + "]";
|
||
}
|
||
} // class SingletonSet
|
||
|
||
/**
|
||
* Obtain an immutable List consisting of a single element. The return value
|
||
* of this method is Serializable, and implements RandomAccess.
|
||
*
|
||
* @param o the single element
|
||
* @return an immutable List containing only o
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
* @since 1.3
|
||
*/
|
||
public static List singletonList(Object o)
|
||
{
|
||
return new SingletonList(o);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #singletonList(Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SingletonList extends AbstractList
|
||
implements Serializable, RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 3093736618740652951L;
|
||
|
||
/**
|
||
* The single element.
|
||
* @serial the singleton
|
||
*/
|
||
private final Object element;
|
||
|
||
/**
|
||
* Construct a singleton.
|
||
* @param o the element
|
||
*/
|
||
SingletonList(Object o)
|
||
{
|
||
element = o;
|
||
}
|
||
|
||
/**
|
||
* The size: always 1!
|
||
*/
|
||
public int size()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Only index 0 is valid.
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
if (index == 0)
|
||
return element;
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractList.
|
||
/**
|
||
* The set only contains one element.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return equals(o, element);
|
||
}
|
||
|
||
/**
|
||
* This is true if the other collection only contains the element.
|
||
*/
|
||
public boolean containsAll(Collection c)
|
||
{
|
||
Iterator i = c.iterator();
|
||
int pos = c.size();
|
||
while (--pos >= 0)
|
||
if (! equals(i.next(), element))
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Speed up the hashcode computation.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return 31 + hashCode(element);
|
||
}
|
||
|
||
/**
|
||
* Either the list has it or not.
|
||
*/
|
||
public int indexOf(Object o)
|
||
{
|
||
return equals(o, element) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* Either the list has it or not.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return equals(o, element) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* Sublists are limited in scope.
|
||
*/
|
||
public List subList(int from, int to)
|
||
{
|
||
if (from == to && (to == 0 || to == 1))
|
||
return EMPTY_LIST;
|
||
if (from == 0 && to == 1)
|
||
return this;
|
||
if (from > to)
|
||
throw new IllegalArgumentException();
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
/**
|
||
* Returning an array is simple.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return new Object[] {element};
|
||
}
|
||
|
||
/**
|
||
* Obvious string.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[" + element + "]";
|
||
}
|
||
} // class SingletonList
|
||
|
||
/**
|
||
* Obtain an immutable Map consisting of a single key-value pair.
|
||
* The return value of this method is Serializable.
|
||
*
|
||
* @param key the single key
|
||
* @param value the single value
|
||
* @return an immutable Map containing only the single key-value pair
|
||
* @see Serializable
|
||
* @since 1.3
|
||
*/
|
||
public static Map singletonMap(Object key, Object value)
|
||
{
|
||
return new SingletonMap(key, value);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #singletonMap(Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SingletonMap extends AbstractMap
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -6979724477215052911L;
|
||
|
||
/**
|
||
* The single key.
|
||
* @serial the singleton key
|
||
*/
|
||
private final Object k;
|
||
|
||
/**
|
||
* The corresponding value.
|
||
* @serial the singleton value
|
||
*/
|
||
private final Object v;
|
||
|
||
/**
|
||
* Cache the entry set.
|
||
*/
|
||
private transient Set entries;
|
||
|
||
/**
|
||
* Construct a singleton.
|
||
* @param key the key
|
||
* @param value the value
|
||
*/
|
||
SingletonMap(Object key, Object value)
|
||
{
|
||
k = key;
|
||
v = value;
|
||
}
|
||
|
||
/**
|
||
* There is a single immutable entry.
|
||
*/
|
||
public Set entrySet()
|
||
{
|
||
if (entries == null)
|
||
entries = singleton(new BasicMapEntry(k, v)
|
||
{
|
||
public Object setValue(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
});
|
||
return entries;
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractMap.
|
||
/**
|
||
* Single entry.
|
||
*/
|
||
public boolean containsKey(Object key)
|
||
{
|
||
return equals(key, k);
|
||
}
|
||
|
||
/**
|
||
* Single entry.
|
||
*/
|
||
public boolean containsValue(Object value)
|
||
{
|
||
return equals(value, v);
|
||
}
|
||
|
||
/**
|
||
* Single entry.
|
||
*/
|
||
public Object get(Object key)
|
||
{
|
||
return equals(key, k) ? v : null;
|
||
}
|
||
|
||
/**
|
||
* Calculate the hashcode directly.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return hashCode(k) ^ hashCode(v);
|
||
}
|
||
|
||
/**
|
||
* Return the keyset.
|
||
*/
|
||
public Set keySet()
|
||
{
|
||
if (keys == null)
|
||
keys = singleton(k);
|
||
return keys;
|
||
}
|
||
|
||
/**
|
||
* The size: always 1!
|
||
*/
|
||
public int size()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Return the values. Technically, a singleton, while more specific than
|
||
* a general Collection, will work. Besides, that's what the JDK uses!
|
||
*/
|
||
public Collection values()
|
||
{
|
||
if (values == null)
|
||
values = singleton(v);
|
||
return values;
|
||
}
|
||
|
||
/**
|
||
* Obvious string.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "{" + k + "=" + v + "}";
|
||
}
|
||
} // class SingletonMap
|
||
|
||
/**
|
||
* Sort a list according to the natural ordering of its elements. The list
|
||
* must be modifiable, but can be of fixed size. The sort algorithm is
|
||
* precisely that used by Arrays.sort(Object[]), which offers guaranteed
|
||
* nlog(n) performance. This implementation dumps the list into an array,
|
||
* sorts the array, and then iterates over the list setting each element from
|
||
* the array.
|
||
*
|
||
* @param l the List to sort
|
||
* @throws ClassCastException if some items are not mutually comparable
|
||
* @throws UnsupportedOperationException if the List is not modifiable
|
||
* @throws NullPointerException if some element is null
|
||
* @see Arrays#sort(Object[])
|
||
*/
|
||
public static void sort(List l)
|
||
{
|
||
sort(l, null);
|
||
}
|
||
|
||
/**
|
||
* Sort a list according to a specified Comparator. The list must be
|
||
* modifiable, but can be of fixed size. The sort algorithm is precisely that
|
||
* used by Arrays.sort(Object[], Comparator), which offers guaranteed
|
||
* nlog(n) performance. This implementation dumps the list into an array,
|
||
* sorts the array, and then iterates over the list setting each element from
|
||
* the array.
|
||
*
|
||
* @param l the List to sort
|
||
* @param c the Comparator specifying the ordering for the elements, or
|
||
* null for natural ordering
|
||
* @throws ClassCastException if c will not compare some pair of items
|
||
* @throws UnsupportedOperationException if the List is not modifiable
|
||
* @throws NullPointerException if null is compared by natural ordering
|
||
* (only possible when c is null)
|
||
* @see Arrays#sort(Object[], Comparator)
|
||
*/
|
||
public static void sort(List l, Comparator c)
|
||
{
|
||
Object[] a = l.toArray();
|
||
Arrays.sort(a, c);
|
||
ListIterator i = l.listIterator(a.length);
|
||
for (int pos = a.length; --pos >= 0; )
|
||
{
|
||
i.previous();
|
||
i.set(a[pos]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Swaps the elements at the specified positions within the list. Equal
|
||
* positions have no effect.
|
||
*
|
||
* @param l the list to work on
|
||
* @param i the first index to swap
|
||
* @param j the second index
|
||
* @throws UnsupportedOperationException if list.set is not supported
|
||
* @throws IndexOutOfBoundsException if either i or j is < 0 or >=
|
||
* list.size()
|
||
* @since 1.4
|
||
*/
|
||
public static void swap(List l, int i, int j)
|
||
{
|
||
l.set(i, l.set(j, l.get(i)));
|
||
}
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) collection wrapper backed by the
|
||
* given collection. Notice that element access through the iterators
|
||
* is thread-safe, but if the collection can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* Collection c = Collections.synchronizedCollection(new Collection(...));
|
||
* ...
|
||
* synchronized (c)
|
||
* {
|
||
* Iterator i = c.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* Since the collection might be a List or a Set, and those have incompatible
|
||
* equals and hashCode requirements, this relies on Object's implementation
|
||
* rather than passing those calls on to the wrapped collection. The returned
|
||
* Collection implements Serializable, but can only be serialized if
|
||
* the collection it wraps is likewise Serializable.
|
||
*
|
||
* @param c the collection to wrap
|
||
* @return a synchronized view of the collection
|
||
* @see Serializable
|
||
*/
|
||
public static Collection synchronizedCollection(Collection c)
|
||
{
|
||
return new SynchronizedCollection(c);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedCollection(Collection)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
* Package visible, so that collections such as the one for
|
||
* Hashtable.values() can specify which object to synchronize on.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
static class SynchronizedCollection
|
||
implements Collection, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 3053995032091335093L;
|
||
|
||
/**
|
||
* The wrapped collection. Package visible for use by subclasses.
|
||
* @serial the real collection
|
||
*/
|
||
final Collection c;
|
||
|
||
/**
|
||
* The object to synchronize on. When an instance is created via public
|
||
* methods, it will be this; but other uses like SynchronizedMap.values()
|
||
* must specify another mutex. Package visible for use by subclasses.
|
||
* @serial the lock
|
||
*/
|
||
final Object mutex;
|
||
|
||
/**
|
||
* Wrap a given collection.
|
||
* @param c the collection to wrap
|
||
* @throws NullPointerException if c is null
|
||
*/
|
||
SynchronizedCollection(Collection c)
|
||
{
|
||
this.c = c;
|
||
mutex = this;
|
||
if (c == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the
|
||
* collection.
|
||
* @param sync the mutex
|
||
* @param c the collection
|
||
*/
|
||
SynchronizedCollection(Object sync, Collection c)
|
||
{
|
||
this.c = c;
|
||
mutex = sync;
|
||
}
|
||
|
||
public boolean add(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.add(o);
|
||
}
|
||
}
|
||
|
||
public boolean addAll(Collection col)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.addAll(col);
|
||
}
|
||
}
|
||
|
||
public void clear()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
c.clear();
|
||
}
|
||
}
|
||
|
||
public boolean contains(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.contains(o);
|
||
}
|
||
}
|
||
|
||
public boolean containsAll(Collection c1)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.containsAll(c1);
|
||
}
|
||
}
|
||
|
||
public boolean isEmpty()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.isEmpty();
|
||
}
|
||
}
|
||
|
||
public Iterator iterator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedIterator(mutex, c.iterator());
|
||
}
|
||
}
|
||
|
||
public boolean remove(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.remove(o);
|
||
}
|
||
}
|
||
|
||
public boolean removeAll(Collection col)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.removeAll(col);
|
||
}
|
||
}
|
||
|
||
public boolean retainAll(Collection col)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.retainAll(col);
|
||
}
|
||
}
|
||
|
||
public int size()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.size();
|
||
}
|
||
}
|
||
|
||
public Object[] toArray()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.toArray();
|
||
}
|
||
}
|
||
|
||
public Object[] toArray(Object[] a)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.toArray(a);
|
||
}
|
||
}
|
||
|
||
public String toString()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.toString();
|
||
}
|
||
}
|
||
} // class SynchronizedCollection
|
||
|
||
/**
|
||
* The implementation of the various iterator methods in the
|
||
* synchronized classes. These iterators must "sync" on the same object
|
||
* as the collection they iterate over.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class SynchronizedIterator implements Iterator
|
||
{
|
||
/**
|
||
* The object to synchronize on. Package visible for use by subclass.
|
||
*/
|
||
final Object mutex;
|
||
|
||
/**
|
||
* The wrapped iterator.
|
||
*/
|
||
private final Iterator i;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper, with the specified sync.
|
||
* @param sync the mutex
|
||
* @param i the wrapped iterator
|
||
*/
|
||
SynchronizedIterator(Object sync, Iterator i)
|
||
{
|
||
this.i = i;
|
||
mutex = sync;
|
||
}
|
||
|
||
public Object next()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return i.next();
|
||
}
|
||
}
|
||
|
||
public boolean hasNext()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return i.hasNext();
|
||
}
|
||
}
|
||
|
||
public void remove()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
i.remove();
|
||
}
|
||
}
|
||
} // class SynchronizedIterator
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) list wrapper backed by the
|
||
* given list. Notice that element access through the iterators
|
||
* is thread-safe, but if the list can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* List l = Collections.synchronizedList(new List(...));
|
||
* ...
|
||
* synchronized (l)
|
||
* {
|
||
* Iterator i = l.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned List implements Serializable, but can only be serialized if
|
||
* the list it wraps is likewise Serializable. In addition, if the wrapped
|
||
* list implements RandomAccess, this does too.
|
||
*
|
||
* @param l the list to wrap
|
||
* @return a synchronized view of the list
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static List synchronizedList(List l)
|
||
{
|
||
if (l instanceof RandomAccess)
|
||
return new SynchronizedRandomAccessList(l);
|
||
return new SynchronizedList(l);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedList(List)} for sequential
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability. Package visible, so that lists such as Vector.subList()
|
||
* can specify which object to synchronize on.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
static class SynchronizedList extends SynchronizedCollection
|
||
implements List
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -7754090372962971524L;
|
||
|
||
/**
|
||
* The wrapped list; stored both here and in the superclass to avoid
|
||
* excessive casting. Package visible for use by subclass.
|
||
* @serial the wrapped list
|
||
*/
|
||
final List list;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
SynchronizedList(List l)
|
||
{
|
||
super(l);
|
||
list = l;
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the list.
|
||
* @param sync the mutex
|
||
* @param l the list
|
||
*/
|
||
SynchronizedList(Object sync, List l)
|
||
{
|
||
super(sync, l);
|
||
list = l;
|
||
}
|
||
|
||
public void add(int index, Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
list.add(index, o);
|
||
}
|
||
}
|
||
|
||
public boolean addAll(int index, Collection c)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.addAll(index, c);
|
||
}
|
||
}
|
||
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.equals(o);
|
||
}
|
||
}
|
||
|
||
public Object get(int index)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.get(index);
|
||
}
|
||
}
|
||
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.hashCode();
|
||
}
|
||
}
|
||
|
||
public int indexOf(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.indexOf(o);
|
||
}
|
||
}
|
||
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.lastIndexOf(o);
|
||
}
|
||
}
|
||
|
||
public ListIterator listIterator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedListIterator(mutex, list.listIterator());
|
||
}
|
||
}
|
||
|
||
public ListIterator listIterator(int index)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedListIterator(mutex, list.listIterator(index));
|
||
}
|
||
}
|
||
|
||
public Object remove(int index)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.remove(index);
|
||
}
|
||
}
|
||
|
||
public Object set(int index, Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.set(index, o);
|
||
}
|
||
}
|
||
|
||
public List subList(int fromIndex, int toIndex)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedList(mutex, list.subList(fromIndex, toIndex));
|
||
}
|
||
}
|
||
} // class SynchronizedList
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedList(List)} for random-access
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SynchronizedRandomAccessList
|
||
extends SynchronizedList implements RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1530674583602358482L;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
SynchronizedRandomAccessList(List l)
|
||
{
|
||
super(l);
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the
|
||
* collection.
|
||
* @param sync the mutex
|
||
* @param l the list
|
||
*/
|
||
SynchronizedRandomAccessList(Object sync, List l)
|
||
{
|
||
super(sync, l);
|
||
}
|
||
|
||
public List subList(int fromIndex, int toIndex)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedRandomAccessList(mutex,
|
||
list.subList(fromIndex,
|
||
toIndex));
|
||
}
|
||
}
|
||
} // class SynchronizedRandomAccessList
|
||
|
||
/**
|
||
* The implementation of {@link SynchronizedList#listIterator()}. This
|
||
* iterator must "sync" on the same object as the list it iterates over.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SynchronizedListIterator
|
||
extends SynchronizedIterator implements ListIterator
|
||
{
|
||
/**
|
||
* The wrapped iterator, stored both here and in the superclass to
|
||
* avoid excessive casting.
|
||
*/
|
||
private final ListIterator li;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper, with the specified sync.
|
||
* @param sync the mutex
|
||
* @param li the wrapped iterator
|
||
*/
|
||
SynchronizedListIterator(Object sync, ListIterator li)
|
||
{
|
||
super(sync, li);
|
||
this.li = li;
|
||
}
|
||
|
||
public void add(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
li.add(o);
|
||
}
|
||
}
|
||
public boolean hasPrevious()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.hasPrevious();
|
||
}
|
||
}
|
||
|
||
public int nextIndex()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.nextIndex();
|
||
}
|
||
}
|
||
|
||
public Object previous()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.previous();
|
||
}
|
||
}
|
||
|
||
public int previousIndex()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.previousIndex();
|
||
}
|
||
}
|
||
|
||
public void set(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
li.set(o);
|
||
}
|
||
}
|
||
} // class SynchronizedListIterator
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) map wrapper backed by the given
|
||
* map. Notice that element access through the collection views and their
|
||
* iterators are thread-safe, but if the map can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* Map m = Collections.synchronizedMap(new Map(...));
|
||
* ...
|
||
* Set s = m.keySet(); // safe outside a synchronized block
|
||
* synchronized (m) // synch on m, not s
|
||
* {
|
||
* Iterator i = s.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned Map implements Serializable, but can only be serialized if
|
||
* the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the map to wrap
|
||
* @return a synchronized view of the map
|
||
* @see Serializable
|
||
*/
|
||
public static Map synchronizedMap(Map m)
|
||
{
|
||
return new SynchronizedMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedMap(Map)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class SynchronizedMap implements Map, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1978198479659022715L;
|
||
|
||
/**
|
||
* The wrapped map.
|
||
* @serial the real map
|
||
*/
|
||
private final Map m;
|
||
|
||
/**
|
||
* The object to synchronize on. When an instance is created via public
|
||
* methods, it will be this; but other uses like
|
||
* SynchronizedSortedMap.subMap() must specify another mutex. Package
|
||
* visible for use by subclass.
|
||
* @serial the lock
|
||
*/
|
||
final Object mutex;
|
||
|
||
/**
|
||
* Cache the entry set.
|
||
*/
|
||
private transient Set entries;
|
||
|
||
/**
|
||
* Cache the key set.
|
||
*/
|
||
private transient Set keys;
|
||
|
||
/**
|
||
* Cache the value collection.
|
||
*/
|
||
private transient Collection values;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param m the map to wrap
|
||
* @throws NullPointerException if m is null
|
||
*/
|
||
SynchronizedMap(Map m)
|
||
{
|
||
this.m = m;
|
||
mutex = this;
|
||
if (m == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the map.
|
||
* @param sync the mutex
|
||
* @param m the map
|
||
*/
|
||
SynchronizedMap(Object sync, Map m)
|
||
{
|
||
this.m = m;
|
||
mutex = sync;
|
||
}
|
||
|
||
public void clear()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
m.clear();
|
||
}
|
||
}
|
||
|
||
public boolean containsKey(Object key)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.containsKey(key);
|
||
}
|
||
}
|
||
|
||
public boolean containsValue(Object value)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.containsValue(value);
|
||
}
|
||
}
|
||
|
||
// This is one of the ickiest cases of nesting I've ever seen. It just
|
||
// means "return a SynchronizedSet, except that the iterator() method
|
||
// returns an SynchronizedIterator whose next() method returns a
|
||
// synchronized wrapper around its normal return value".
|
||
public Set entrySet()
|
||
{
|
||
// Define this here to spare some nesting.
|
||
class SynchronizedMapEntry implements Map.Entry
|
||
{
|
||
final Map.Entry e;
|
||
SynchronizedMapEntry(Object o)
|
||
{
|
||
e = (Map.Entry) o;
|
||
}
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.equals(o);
|
||
}
|
||
}
|
||
public Object getKey()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.getKey();
|
||
}
|
||
}
|
||
public Object getValue()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.getValue();
|
||
}
|
||
}
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.hashCode();
|
||
}
|
||
}
|
||
public Object setValue(Object value)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.setValue(value);
|
||
}
|
||
}
|
||
public String toString()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.toString();
|
||
}
|
||
}
|
||
} // class SynchronizedMapEntry
|
||
|
||
// Now the actual code.
|
||
if (entries == null)
|
||
synchronized (mutex)
|
||
{
|
||
entries = new SynchronizedSet(mutex, m.entrySet())
|
||
{
|
||
public Iterator iterator()
|
||
{
|
||
synchronized (super.mutex)
|
||
{
|
||
return new SynchronizedIterator(super.mutex, c.iterator())
|
||
{
|
||
public Object next()
|
||
{
|
||
synchronized (super.mutex)
|
||
{
|
||
return new SynchronizedMapEntry(super.next());
|
||
}
|
||
}
|
||
};
|
||
}
|
||
}
|
||
};
|
||
}
|
||
return entries;
|
||
}
|
||
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.equals(o);
|
||
}
|
||
}
|
||
|
||
public Object get(Object key)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.get(key);
|
||
}
|
||
}
|
||
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.hashCode();
|
||
}
|
||
}
|
||
|
||
public boolean isEmpty()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.isEmpty();
|
||
}
|
||
}
|
||
|
||
public Set keySet()
|
||
{
|
||
if (keys == null)
|
||
synchronized (mutex)
|
||
{
|
||
keys = new SynchronizedSet(mutex, m.keySet());
|
||
}
|
||
return keys;
|
||
}
|
||
|
||
public Object put(Object key, Object value)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.put(key, value);
|
||
}
|
||
}
|
||
|
||
public void putAll(Map map)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
m.putAll(map);
|
||
}
|
||
}
|
||
|
||
public Object remove(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.remove(o);
|
||
}
|
||
}
|
||
|
||
public int size()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.size();
|
||
}
|
||
}
|
||
|
||
public String toString()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.toString();
|
||
}
|
||
}
|
||
|
||
public Collection values()
|
||
{
|
||
if (values == null)
|
||
synchronized (mutex)
|
||
{
|
||
values = new SynchronizedCollection(mutex, m.values());
|
||
}
|
||
return values;
|
||
}
|
||
} // class SynchronizedMap
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) set wrapper backed by the given
|
||
* set. Notice that element access through the iterator is thread-safe, but
|
||
* if the set can be structurally modified (adding or removing elements)
|
||
* then you should synchronize around the iteration to avoid
|
||
* non-deterministic behavior:<br>
|
||
* <pre>
|
||
* Set s = Collections.synchronizedSet(new Set(...));
|
||
* ...
|
||
* synchronized (s)
|
||
* {
|
||
* Iterator i = s.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned Set implements Serializable, but can only be serialized if
|
||
* the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the set to wrap
|
||
* @return a synchronized view of the set
|
||
* @see Serializable
|
||
*/
|
||
public static Set synchronizedSet(Set s)
|
||
{
|
||
return new SynchronizedSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSet(Set)}. This class
|
||
* name is required for compatibility with Sun's JDK serializability.
|
||
* Package visible, so that sets such as Hashtable.keySet()
|
||
* can specify which object to synchronize on.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
static class SynchronizedSet extends SynchronizedCollection
|
||
implements Set
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 487447009682186044L;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param s the set to wrap
|
||
* @throws NullPointerException if s is null
|
||
*/
|
||
SynchronizedSet(Set s)
|
||
{
|
||
super(s);
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the set.
|
||
* @param sync the mutex
|
||
* @param s the set
|
||
*/
|
||
SynchronizedSet(Object sync, Set s)
|
||
{
|
||
super(sync, s);
|
||
}
|
||
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.equals(o);
|
||
}
|
||
}
|
||
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.hashCode();
|
||
}
|
||
}
|
||
} // class SynchronizedSet
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) sorted map wrapper backed by the
|
||
* given map. Notice that element access through the collection views,
|
||
* subviews, and their iterators are thread-safe, but if the map can be
|
||
* structurally modified (adding or removing elements) then you should
|
||
* synchronize around the iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* SortedMap m = Collections.synchronizedSortedMap(new SortedMap(...));
|
||
* ...
|
||
* Set s = m.keySet(); // safe outside a synchronized block
|
||
* SortedMap m2 = m.headMap(foo); // safe outside a synchronized block
|
||
* Set s2 = m2.keySet(); // safe outside a synchronized block
|
||
* synchronized (m) // synch on m, not m2, s or s2
|
||
* {
|
||
* Iterator i = s.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* i = s2.iterator();
|
||
* while (i.hasNext())
|
||
* bar(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned SortedMap implements Serializable, but can only be
|
||
* serialized if the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the sorted map to wrap
|
||
* @return a synchronized view of the sorted map
|
||
* @see Serializable
|
||
*/
|
||
public static SortedMap synchronizedSortedMap(SortedMap m)
|
||
{
|
||
return new SynchronizedSortedMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSortedMap(SortedMap)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SynchronizedSortedMap extends SynchronizedMap
|
||
implements SortedMap
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -8798146769416483793L;
|
||
|
||
/**
|
||
* The wrapped map; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped map
|
||
*/
|
||
private final SortedMap sm;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param sm the map to wrap
|
||
* @throws NullPointerException if sm is null
|
||
*/
|
||
SynchronizedSortedMap(SortedMap sm)
|
||
{
|
||
super(sm);
|
||
this.sm = sm;
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the map.
|
||
* @param sync the mutex
|
||
* @param sm the map
|
||
*/
|
||
SynchronizedSortedMap(Object sync, SortedMap sm)
|
||
{
|
||
super(sync, sm);
|
||
this.sm = sm;
|
||
}
|
||
|
||
public Comparator comparator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return sm.comparator();
|
||
}
|
||
}
|
||
|
||
public Object firstKey()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return sm.firstKey();
|
||
}
|
||
}
|
||
|
||
public SortedMap headMap(Object toKey)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedMap(mutex, sm.headMap(toKey));
|
||
}
|
||
}
|
||
|
||
public Object lastKey()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return sm.lastKey();
|
||
}
|
||
}
|
||
|
||
public SortedMap subMap(Object fromKey, Object toKey)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedMap(mutex, sm.subMap(fromKey, toKey));
|
||
}
|
||
}
|
||
|
||
public SortedMap tailMap(Object fromKey)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedMap(mutex, sm.tailMap(fromKey));
|
||
}
|
||
}
|
||
} // class SynchronizedSortedMap
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) sorted set wrapper backed by the
|
||
* given set. Notice that element access through the iterator and through
|
||
* subviews are thread-safe, but if the set can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* SortedSet s = Collections.synchronizedSortedSet(new SortedSet(...));
|
||
* ...
|
||
* SortedSet s2 = s.headSet(foo); // safe outside a synchronized block
|
||
* synchronized (s) // synch on s, not s2
|
||
* {
|
||
* Iterator i = s2.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned SortedSet implements Serializable, but can only be
|
||
* serialized if the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the sorted set to wrap
|
||
* @return a synchronized view of the sorted set
|
||
* @see Serializable
|
||
*/
|
||
public static SortedSet synchronizedSortedSet(SortedSet s)
|
||
{
|
||
return new SynchronizedSortedSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSortedSet(SortedSet)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class SynchronizedSortedSet extends SynchronizedSet
|
||
implements SortedSet
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 8695801310862127406L;
|
||
|
||
/**
|
||
* The wrapped set; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped set
|
||
*/
|
||
private final SortedSet ss;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param ss the set to wrap
|
||
* @throws NullPointerException if ss is null
|
||
*/
|
||
SynchronizedSortedSet(SortedSet ss)
|
||
{
|
||
super(ss);
|
||
this.ss = ss;
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the set.
|
||
* @param sync the mutex
|
||
* @param l the list
|
||
*/
|
||
SynchronizedSortedSet(Object sync, SortedSet ss)
|
||
{
|
||
super(sync, ss);
|
||
this.ss = ss;
|
||
}
|
||
|
||
public Comparator comparator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return ss.comparator();
|
||
}
|
||
}
|
||
|
||
public Object first()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return ss.first();
|
||
}
|
||
}
|
||
|
||
public SortedSet headSet(Object toElement)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedSet(mutex, ss.headSet(toElement));
|
||
}
|
||
}
|
||
|
||
public Object last()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return ss.last();
|
||
}
|
||
}
|
||
|
||
public SortedSet subSet(Object fromElement, Object toElement)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedSet(mutex,
|
||
ss.subSet(fromElement, toElement));
|
||
}
|
||
}
|
||
|
||
public SortedSet tailSet(Object fromElement)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedSet(mutex, ss.tailSet(fromElement));
|
||
}
|
||
}
|
||
} // class SynchronizedSortedSet
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given collection. This allows
|
||
* "read-only" access, although changes in the backing collection show up
|
||
* in this view. Attempts to modify the collection directly or via iterators
|
||
* will fail with {@link UnsupportedOperationException}.
|
||
* <p>
|
||
*
|
||
* Since the collection might be a List or a Set, and those have incompatible
|
||
* equals and hashCode requirements, this relies on Object's implementation
|
||
* rather than passing those calls on to the wrapped collection. The returned
|
||
* Collection implements Serializable, but can only be serialized if
|
||
* the collection it wraps is likewise Serializable.
|
||
*
|
||
* @param c the collection to wrap
|
||
* @return a read-only view of the collection
|
||
* @see Serializable
|
||
*/
|
||
public static Collection unmodifiableCollection(Collection c)
|
||
{
|
||
return new UnmodifiableCollection(c);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableCollection(Collection)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableCollection
|
||
implements Collection, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1820017752578914078L;
|
||
|
||
/**
|
||
* The wrapped collection. Package visible for use by subclasses.
|
||
* @serial the real collection
|
||
*/
|
||
final Collection c;
|
||
|
||
/**
|
||
* Wrap a given collection.
|
||
* @param c the collection to wrap
|
||
* @throws NullPointerException if c is null
|
||
*/
|
||
UnmodifiableCollection(Collection c)
|
||
{
|
||
this.c = c;
|
||
if (c == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
public boolean add(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean addAll(Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public void clear()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean contains(Object o)
|
||
{
|
||
return c.contains(o);
|
||
}
|
||
|
||
public boolean containsAll(Collection c1)
|
||
{
|
||
return c.containsAll(c1);
|
||
}
|
||
|
||
public boolean isEmpty()
|
||
{
|
||
return c.isEmpty();
|
||
}
|
||
|
||
public Iterator iterator()
|
||
{
|
||
return new UnmodifiableIterator(c.iterator());
|
||
}
|
||
|
||
public boolean remove(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean removeAll(Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean retainAll(Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public int size()
|
||
{
|
||
return c.size();
|
||
}
|
||
|
||
public Object[] toArray()
|
||
{
|
||
return c.toArray();
|
||
}
|
||
|
||
public Object[] toArray(Object[] a)
|
||
{
|
||
return c.toArray(a);
|
||
}
|
||
|
||
public String toString()
|
||
{
|
||
return c.toString();
|
||
}
|
||
} // class UnmodifiableCollection
|
||
|
||
/**
|
||
* The implementation of the various iterator methods in the
|
||
* unmodifiable classes.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableIterator implements Iterator
|
||
{
|
||
/**
|
||
* The wrapped iterator.
|
||
*/
|
||
private final Iterator i;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper.
|
||
* @param i the wrapped iterator
|
||
*/
|
||
UnmodifiableIterator(Iterator i)
|
||
{
|
||
this.i = i;
|
||
}
|
||
|
||
public Object next()
|
||
{
|
||
return i.next();
|
||
}
|
||
|
||
public boolean hasNext()
|
||
{
|
||
return i.hasNext();
|
||
}
|
||
|
||
public void remove()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
} // class UnmodifiableIterator
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given list. This allows
|
||
* "read-only" access, although changes in the backing list show up
|
||
* in this view. Attempts to modify the list directly, via iterators, or
|
||
* via sublists, will fail with {@link UnsupportedOperationException}.
|
||
* <p>
|
||
*
|
||
* The returned List implements Serializable, but can only be serialized if
|
||
* the list it wraps is likewise Serializable. In addition, if the wrapped
|
||
* list implements RandomAccess, this does too.
|
||
*
|
||
* @param l the list to wrap
|
||
* @return a read-only view of the list
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static List unmodifiableList(List l)
|
||
{
|
||
if (l instanceof RandomAccess)
|
||
return new UnmodifiableRandomAccessList(l);
|
||
return new UnmodifiableList(l);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableList(List)} for sequential
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableList extends UnmodifiableCollection
|
||
implements List
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -283967356065247728L;
|
||
|
||
|
||
/**
|
||
* The wrapped list; stored both here and in the superclass to avoid
|
||
* excessive casting. Package visible for use by subclass.
|
||
* @serial the wrapped list
|
||
*/
|
||
final List list;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
UnmodifiableList(List l)
|
||
{
|
||
super(l);
|
||
list = l;
|
||
}
|
||
|
||
public void add(int index, Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean addAll(int index, Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean equals(Object o)
|
||
{
|
||
return list.equals(o);
|
||
}
|
||
|
||
public Object get(int index)
|
||
{
|
||
return list.get(index);
|
||
}
|
||
|
||
public int hashCode()
|
||
{
|
||
return list.hashCode();
|
||
}
|
||
|
||
public int indexOf(Object o)
|
||
{
|
||
return list.indexOf(o);
|
||
}
|
||
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return list.lastIndexOf(o);
|
||
}
|
||
|
||
public ListIterator listIterator()
|
||
{
|
||
return new UnmodifiableListIterator(list.listIterator());
|
||
}
|
||
|
||
public ListIterator listIterator(int index)
|
||
{
|
||
return new UnmodifiableListIterator(list.listIterator(index));
|
||
}
|
||
|
||
public Object remove(int index)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public Object set(int index, Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public List subList(int fromIndex, int toIndex)
|
||
{
|
||
return unmodifiableList(list.subList(fromIndex, toIndex));
|
||
}
|
||
} // class UnmodifiableList
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableList(List)} for random-access
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class UnmodifiableRandomAccessList
|
||
extends UnmodifiableList implements RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -2542308836966382001L;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
UnmodifiableRandomAccessList(List l)
|
||
{
|
||
super(l);
|
||
}
|
||
} // class UnmodifiableRandomAccessList
|
||
|
||
/**
|
||
* The implementation of {@link UnmodifiableList#listIterator()}.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class UnmodifiableListIterator
|
||
extends UnmodifiableIterator implements ListIterator
|
||
{
|
||
/**
|
||
* The wrapped iterator, stored both here and in the superclass to
|
||
* avoid excessive casting.
|
||
*/
|
||
private final ListIterator li;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper.
|
||
* @param li the wrapped iterator
|
||
*/
|
||
UnmodifiableListIterator(ListIterator li)
|
||
{
|
||
super(li);
|
||
this.li = li;
|
||
}
|
||
|
||
public void add(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean hasPrevious()
|
||
{
|
||
return li.hasPrevious();
|
||
}
|
||
|
||
public int nextIndex()
|
||
{
|
||
return li.nextIndex();
|
||
}
|
||
|
||
public Object previous()
|
||
{
|
||
return li.previous();
|
||
}
|
||
|
||
public int previousIndex()
|
||
{
|
||
return li.previousIndex();
|
||
}
|
||
|
||
public void set(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
} // class UnmodifiableListIterator
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given map. This allows "read-only"
|
||
* access, although changes in the backing map show up in this view.
|
||
* Attempts to modify the map directly, or via collection views or their
|
||
* iterators will fail with {@link UnsupportedOperationException}.
|
||
* <p>
|
||
*
|
||
* The returned Map implements Serializable, but can only be serialized if
|
||
* the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the map to wrap
|
||
* @return a read-only view of the map
|
||
* @see Serializable
|
||
*/
|
||
public static Map unmodifiableMap(Map m)
|
||
{
|
||
return new UnmodifiableMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableMap(Map)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableMap implements Map, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -1034234728574286014L;
|
||
|
||
/**
|
||
* The wrapped map.
|
||
* @serial the real map
|
||
*/
|
||
private final Map m;
|
||
|
||
/**
|
||
* Cache the entry set.
|
||
*/
|
||
private transient Set entries;
|
||
|
||
/**
|
||
* Cache the key set.
|
||
*/
|
||
private transient Set keys;
|
||
|
||
/**
|
||
* Cache the value collection.
|
||
*/
|
||
private transient Collection values;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param m the map to wrap
|
||
* @throws NullPointerException if m is null
|
||
*/
|
||
UnmodifiableMap(Map m)
|
||
{
|
||
this.m = m;
|
||
if (m == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
public void clear()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public boolean containsKey(Object key)
|
||
{
|
||
return m.containsKey(key);
|
||
}
|
||
|
||
public boolean containsValue(Object value)
|
||
{
|
||
return m.containsValue(value);
|
||
}
|
||
|
||
public Set entrySet()
|
||
{
|
||
if (entries == null)
|
||
entries = new UnmodifiableEntrySet(m.entrySet());
|
||
return entries;
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link UnmodifiableMap#entrySet()}. This class
|
||
* name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static final class UnmodifiableEntrySet extends UnmodifiableSet
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 7854390611657943733L;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param s the set to wrap
|
||
*/
|
||
UnmodifiableEntrySet(Set s)
|
||
{
|
||
super(s);
|
||
}
|
||
|
||
// The iterator must return unmodifiable map entries.
|
||
public Iterator iterator()
|
||
{
|
||
return new UnmodifiableIterator(c.iterator())
|
||
{
|
||
public Object next()
|
||
{
|
||
final Map.Entry e = (Map.Entry) super.next();
|
||
return new Map.Entry()
|
||
{
|
||
public boolean equals(Object o)
|
||
{
|
||
return e.equals(o);
|
||
}
|
||
public Object getKey()
|
||
{
|
||
return e.getKey();
|
||
}
|
||
public Object getValue()
|
||
{
|
||
return e.getValue();
|
||
}
|
||
public int hashCode()
|
||
{
|
||
return e.hashCode();
|
||
}
|
||
public Object setValue(Object value)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
public String toString()
|
||
{
|
||
return e.toString();
|
||
}
|
||
};
|
||
}
|
||
};
|
||
}
|
||
} // class UnmodifiableEntrySet
|
||
|
||
public boolean equals(Object o)
|
||
{
|
||
return m.equals(o);
|
||
}
|
||
|
||
public Object get(Object key)
|
||
{
|
||
return m.get(key);
|
||
}
|
||
|
||
public Object put(Object key, Object value)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public int hashCode()
|
||
{
|
||
return m.hashCode();
|
||
}
|
||
|
||
public boolean isEmpty()
|
||
{
|
||
return m.isEmpty();
|
||
}
|
||
|
||
public Set keySet()
|
||
{
|
||
if (keys == null)
|
||
keys = new UnmodifiableSet(m.keySet());
|
||
return keys;
|
||
}
|
||
|
||
public void putAll(Map m)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public Object remove(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
public int size()
|
||
{
|
||
return m.size();
|
||
}
|
||
|
||
public String toString()
|
||
{
|
||
return m.toString();
|
||
}
|
||
|
||
public Collection values()
|
||
{
|
||
if (values == null)
|
||
values = new UnmodifiableCollection(m.values());
|
||
return values;
|
||
}
|
||
} // class UnmodifiableMap
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given set. This allows
|
||
* "read-only" access, although changes in the backing set show up
|
||
* in this view. Attempts to modify the set directly or via iterators
|
||
* will fail with {@link UnsupportedOperationException}.
|
||
* <p>
|
||
*
|
||
* The returned Set implements Serializable, but can only be serialized if
|
||
* the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the set to wrap
|
||
* @return a read-only view of the set
|
||
* @see Serializable
|
||
*/
|
||
public static Set unmodifiableSet(Set s)
|
||
{
|
||
return new UnmodifiableSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableSet(Set)}. This class
|
||
* name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableSet extends UnmodifiableCollection
|
||
implements Set
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -9215047833775013803L;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param s the set to wrap
|
||
* @throws NullPointerException if s is null
|
||
*/
|
||
UnmodifiableSet(Set s)
|
||
{
|
||
super(s);
|
||
}
|
||
|
||
public boolean equals(Object o)
|
||
{
|
||
return c.equals(o);
|
||
}
|
||
|
||
public int hashCode()
|
||
{
|
||
return c.hashCode();
|
||
}
|
||
} // class UnmodifiableSet
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given sorted map. This allows
|
||
* "read-only" access, although changes in the backing map show up in this
|
||
* view. Attempts to modify the map directly, via subviews, via collection
|
||
* views, or iterators, will fail with {@link UnsupportedOperationException}.
|
||
* <p>
|
||
*
|
||
* The returned SortedMap implements Serializable, but can only be
|
||
* serialized if the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the map to wrap
|
||
* @return a read-only view of the map
|
||
* @see Serializable
|
||
*/
|
||
public static SortedMap unmodifiableSortedMap(SortedMap m)
|
||
{
|
||
return new UnmodifiableSortedMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableSortedMap(SortedMap)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableSortedMap extends UnmodifiableMap
|
||
implements SortedMap
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -8806743815996713206L;
|
||
|
||
/**
|
||
* The wrapped map; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped map
|
||
*/
|
||
private final SortedMap sm;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param sm the map to wrap
|
||
* @throws NullPointerException if sm is null
|
||
*/
|
||
UnmodifiableSortedMap(SortedMap sm)
|
||
{
|
||
super(sm);
|
||
this.sm = sm;
|
||
}
|
||
|
||
public Comparator comparator()
|
||
{
|
||
return sm.comparator();
|
||
}
|
||
|
||
public Object firstKey()
|
||
{
|
||
return sm.firstKey();
|
||
}
|
||
|
||
public SortedMap headMap(Object toKey)
|
||
{
|
||
return new UnmodifiableSortedMap(sm.headMap(toKey));
|
||
}
|
||
|
||
public Object lastKey()
|
||
{
|
||
return sm.lastKey();
|
||
}
|
||
|
||
public SortedMap subMap(Object fromKey, Object toKey)
|
||
{
|
||
return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey));
|
||
}
|
||
|
||
public SortedMap tailMap(Object fromKey)
|
||
{
|
||
return new UnmodifiableSortedMap(sm.tailMap(fromKey));
|
||
}
|
||
} // class UnmodifiableSortedMap
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given sorted set. This allows
|
||
* "read-only" access, although changes in the backing set show up
|
||
* in this view. Attempts to modify the set directly, via subsets, or via
|
||
* iterators, will fail with {@link UnsupportedOperationException}.
|
||
* <p>
|
||
*
|
||
* The returns SortedSet implements Serializable, but can only be
|
||
* serialized if the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the set to wrap
|
||
* @return a read-only view of the set
|
||
* @see Serializable
|
||
*/
|
||
public static SortedSet unmodifiableSortedSet(SortedSet s)
|
||
{
|
||
return new UnmodifiableSortedSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSortedMap(SortedMap)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake <ebb9@email.byu.edu>
|
||
*/
|
||
private static class UnmodifiableSortedSet extends UnmodifiableSet
|
||
implements SortedSet
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -4929149591599911165L;
|
||
|
||
/**
|
||
* The wrapped set; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped set
|
||
*/
|
||
private SortedSet ss;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param ss the set to wrap
|
||
* @throws NullPointerException if ss is null
|
||
*/
|
||
UnmodifiableSortedSet(SortedSet ss)
|
||
{
|
||
super(ss);
|
||
this.ss = ss;
|
||
}
|
||
|
||
public Comparator comparator()
|
||
{
|
||
return ss.comparator();
|
||
}
|
||
|
||
public Object first()
|
||
{
|
||
return ss.first();
|
||
}
|
||
|
||
public SortedSet headSet(Object toElement)
|
||
{
|
||
return new UnmodifiableSortedSet(ss.headSet(toElement));
|
||
}
|
||
|
||
public Object last()
|
||
{
|
||
return ss.last();
|
||
}
|
||
|
||
public SortedSet subSet(Object fromElement, Object toElement)
|
||
{
|
||
return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement));
|
||
}
|
||
|
||
public SortedSet tailSet(Object fromElement)
|
||
{
|
||
return new UnmodifiableSortedSet(ss.tailSet(fromElement));
|
||
}
|
||
} // class UnmodifiableSortedSet
|
||
} // class Collections
|