jaroslav@597: /* jaroslav@597: * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. jaroslav@597: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@597: * jaroslav@597: * This code is free software; you can redistribute it and/or modify it jaroslav@597: * under the terms of the GNU General Public License version 2 only, as jaroslav@597: * published by the Free Software Foundation. Oracle designates this jaroslav@597: * particular file as subject to the "Classpath" exception as provided jaroslav@597: * by Oracle in the LICENSE file that accompanied this code. jaroslav@597: * jaroslav@597: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@597: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@597: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@597: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@597: * accompanied this code). jaroslav@597: * jaroslav@597: * You should have received a copy of the GNU General Public License version jaroslav@597: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@597: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@597: * jaroslav@597: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@597: * or visit www.oracle.com if you need additional information or have any jaroslav@597: * questions. jaroslav@597: */ jaroslav@597: jaroslav@597: package java.util; jaroslav@597: import java.io.Serializable; jaroslav@597: import java.io.IOException; jaroslav@597: import java.lang.reflect.Array; jaroslav@597: jaroslav@597: /** jaroslav@597: * This class consists exclusively of static methods that operate on or return jaroslav@597: * collections. It contains polymorphic algorithms that operate on jaroslav@597: * collections, "wrappers", which return a new collection backed by a jaroslav@597: * specified collection, and a few other odds and ends. jaroslav@597: * jaroslav@597: *

The methods of this class all throw a NullPointerException jaroslav@597: * if the collections or class objects provided to them are null. jaroslav@597: * jaroslav@597: *

The documentation for the polymorphic algorithms contained in this class jaroslav@597: * generally includes a brief description of the implementation. Such jaroslav@597: * descriptions should be regarded as implementation notes, rather than jaroslav@597: * parts of the specification. Implementors should feel free to jaroslav@597: * substitute other algorithms, so long as the specification itself is adhered jaroslav@597: * to. (For example, the algorithm used by sort does not have to be jaroslav@597: * a mergesort, but it does have to be stable.) jaroslav@597: * jaroslav@597: *

The "destructive" algorithms contained in this class, that is, the jaroslav@597: * algorithms that modify the collection on which they operate, are specified jaroslav@597: * to throw UnsupportedOperationException if the collection does not jaroslav@597: * support the appropriate mutation primitive(s), such as the set jaroslav@597: * method. These algorithms may, but are not required to, throw this jaroslav@597: * exception if an invocation would have no effect on the collection. For jaroslav@597: * example, invoking the sort method on an unmodifiable list that is jaroslav@597: * already sorted may or may not throw UnsupportedOperationException. jaroslav@597: * jaroslav@597: *

This class is a member of the jaroslav@597: * jaroslav@597: * Java Collections Framework. jaroslav@597: * jaroslav@597: * @author Josh Bloch jaroslav@597: * @author Neal Gafter jaroslav@597: * @see Collection jaroslav@597: * @see Set jaroslav@597: * @see List jaroslav@597: * @see Map jaroslav@597: * @since 1.2 jaroslav@597: */ jaroslav@597: jaroslav@597: public class Collections { jaroslav@597: // Suppresses default constructor, ensuring non-instantiability. jaroslav@597: private Collections() { jaroslav@597: } jaroslav@597: jaroslav@597: // Algorithms jaroslav@597: jaroslav@597: /* jaroslav@597: * Tuning parameters for algorithms - Many of the List algorithms have jaroslav@597: * two implementations, one of which is appropriate for RandomAccess jaroslav@597: * lists, the other for "sequential." Often, the random access variant jaroslav@597: * yields better performance on small sequential access lists. The jaroslav@597: * tuning parameters below determine the cutoff point for what constitutes jaroslav@597: * a "small" sequential access list for each algorithm. The values below jaroslav@597: * were empirically determined to work well for LinkedList. Hopefully jaroslav@597: * they should be reasonable for other sequential access List jaroslav@597: * implementations. Those doing performance work on this code would jaroslav@597: * do well to validate the values of these parameters from time to time. jaroslav@597: * (The first word of each tuning parameter name is the algorithm to which jaroslav@597: * it applies.) jaroslav@597: */ jaroslav@597: private static final int BINARYSEARCH_THRESHOLD = 5000; jaroslav@597: private static final int REVERSE_THRESHOLD = 18; jaroslav@597: private static final int SHUFFLE_THRESHOLD = 5; jaroslav@597: private static final int FILL_THRESHOLD = 25; jaroslav@597: private static final int ROTATE_THRESHOLD = 100; jaroslav@597: private static final int COPY_THRESHOLD = 10; jaroslav@597: private static final int REPLACEALL_THRESHOLD = 11; jaroslav@597: private static final int INDEXOFSUBLIST_THRESHOLD = 35; jaroslav@597: jaroslav@597: /** jaroslav@597: * Sorts the specified list into ascending order, according to the jaroslav@597: * {@linkplain Comparable natural ordering} of its elements. jaroslav@597: * All elements in the list must implement the {@link Comparable} jaroslav@597: * interface. Furthermore, all elements in the list must be jaroslav@597: * mutually comparable (that is, {@code e1.compareTo(e2)} jaroslav@597: * must not throw a {@code ClassCastException} for any elements jaroslav@597: * {@code e1} and {@code e2} in the list). jaroslav@597: * jaroslav@597: *

This sort is guaranteed to be stable: equal elements will jaroslav@597: * not be reordered as a result of the sort. jaroslav@597: * jaroslav@597: *

The specified list must be modifiable, but need not be resizable. jaroslav@597: * jaroslav@597: *

Implementation note: This implementation is a stable, adaptive, jaroslav@597: * iterative mergesort that requires far fewer than n lg(n) comparisons jaroslav@597: * when the input array is partially sorted, while offering the jaroslav@597: * performance of a traditional mergesort when the input array is jaroslav@597: * randomly ordered. If the input array is nearly sorted, the jaroslav@597: * implementation requires approximately n comparisons. Temporary jaroslav@597: * storage requirements vary from a small constant for nearly sorted jaroslav@597: * input arrays to n/2 object references for randomly ordered input jaroslav@597: * arrays. jaroslav@597: * jaroslav@597: *

The implementation takes equal advantage of ascending and jaroslav@597: * descending order in its input array, and can take advantage of jaroslav@597: * ascending and descending order in different parts of the same jaroslav@597: * input array. It is well-suited to merging two or more sorted arrays: jaroslav@597: * simply concatenate the arrays and sort the resulting array. jaroslav@597: * jaroslav@597: *

The implementation was adapted from Tim Peters's list sort for Python jaroslav@597: * ( jaroslav@597: * TimSort). It uses techiques from Peter McIlroy's "Optimistic jaroslav@597: * Sorting and Information Theoretic Complexity", in Proceedings of the jaroslav@597: * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, jaroslav@597: * January 1993. jaroslav@597: * jaroslav@597: *

This implementation dumps the specified list into an array, sorts jaroslav@597: * the array, and iterates over the list resetting each element jaroslav@597: * from the corresponding position in the array. This avoids the jaroslav@597: * n2 log(n) performance that would result from attempting jaroslav@597: * to sort a linked list in place. jaroslav@597: * jaroslav@597: * @param list the list to be sorted. jaroslav@597: * @throws ClassCastException if the list contains elements that are not jaroslav@597: * mutually comparable (for example, strings and integers). jaroslav@597: * @throws UnsupportedOperationException if the specified list's jaroslav@597: * list-iterator does not support the {@code set} operation. jaroslav@597: * @throws IllegalArgumentException (optional) if the implementation jaroslav@597: * detects that the natural ordering of the list elements is jaroslav@597: * found to violate the {@link Comparable} contract jaroslav@597: */ jaroslav@597: public static > void sort(List list) { jaroslav@597: Object[] a = list.toArray(); jaroslav@597: Arrays.sort(a); jaroslav@597: ListIterator i = list.listIterator(); jaroslav@597: for (int j=0; jmutually jaroslav@597: * comparable using the specified comparator (that is, jaroslav@597: * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} jaroslav@597: * for any elements {@code e1} and {@code e2} in the list). jaroslav@597: * jaroslav@597: *

This sort is guaranteed to be stable: equal elements will jaroslav@597: * not be reordered as a result of the sort. jaroslav@597: * jaroslav@597: *

The specified list must be modifiable, but need not be resizable. jaroslav@597: * jaroslav@597: *

Implementation note: This implementation is a stable, adaptive, jaroslav@597: * iterative mergesort that requires far fewer than n lg(n) comparisons jaroslav@597: * when the input array is partially sorted, while offering the jaroslav@597: * performance of a traditional mergesort when the input array is jaroslav@597: * randomly ordered. If the input array is nearly sorted, the jaroslav@597: * implementation requires approximately n comparisons. Temporary jaroslav@597: * storage requirements vary from a small constant for nearly sorted jaroslav@597: * input arrays to n/2 object references for randomly ordered input jaroslav@597: * arrays. jaroslav@597: * jaroslav@597: *

The implementation takes equal advantage of ascending and jaroslav@597: * descending order in its input array, and can take advantage of jaroslav@597: * ascending and descending order in different parts of the same jaroslav@597: * input array. It is well-suited to merging two or more sorted arrays: jaroslav@597: * simply concatenate the arrays and sort the resulting array. jaroslav@597: * jaroslav@597: *

The implementation was adapted from Tim Peters's list sort for Python jaroslav@597: * ( jaroslav@597: * TimSort). It uses techiques from Peter McIlroy's "Optimistic jaroslav@597: * Sorting and Information Theoretic Complexity", in Proceedings of the jaroslav@597: * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, jaroslav@597: * January 1993. jaroslav@597: * jaroslav@597: *

This implementation dumps the specified list into an array, sorts jaroslav@597: * the array, and iterates over the list resetting each element jaroslav@597: * from the corresponding position in the array. This avoids the jaroslav@597: * n2 log(n) performance that would result from attempting jaroslav@597: * to sort a linked list in place. jaroslav@597: * jaroslav@597: * @param list the list to be sorted. jaroslav@597: * @param c the comparator to determine the order of the list. A jaroslav@597: * {@code null} value indicates that the elements' natural jaroslav@597: * ordering should be used. jaroslav@597: * @throws ClassCastException if the list contains elements that are not jaroslav@597: * mutually comparable using the specified comparator. jaroslav@597: * @throws UnsupportedOperationException if the specified list's jaroslav@597: * list-iterator does not support the {@code set} operation. jaroslav@597: * @throws IllegalArgumentException (optional) if the comparator is jaroslav@597: * found to violate the {@link Comparator} contract jaroslav@597: */ jaroslav@597: public static void sort(List list, Comparator c) { jaroslav@597: Object[] a = list.toArray(); jaroslav@597: Arrays.sort(a, (Comparator)c); jaroslav@597: ListIterator i = list.listIterator(); jaroslav@597: for (int j=0; jThis method runs in log(n) time for a "random access" list (which jaroslav@597: * provides near-constant-time positional access). If the specified list jaroslav@597: * does not implement the {@link RandomAccess} interface and is large, jaroslav@597: * this method will do an iterator-based binary search that performs jaroslav@597: * O(n) link traversals and O(log n) element comparisons. jaroslav@597: * jaroslav@597: * @param list the list to be searched. jaroslav@597: * @param key the key to be searched for. jaroslav@597: * @return the index of the search key, if it is contained in the list; jaroslav@597: * otherwise, (-(insertion point) - 1). The jaroslav@597: * insertion point is defined as the point at which the jaroslav@597: * key would be inserted into the list: the index of the first jaroslav@597: * element greater than the key, or list.size() if all jaroslav@597: * elements in the list are less than the specified key. Note jaroslav@597: * that this guarantees that the return value will be >= 0 if jaroslav@597: * and only if the key is found. jaroslav@597: * @throws ClassCastException if the list contains elements that are not jaroslav@597: * mutually comparable (for example, strings and jaroslav@597: * integers), or the search key is not mutually comparable jaroslav@597: * with the elements of the list. jaroslav@597: */ jaroslav@597: public static jaroslav@597: int binarySearch(List> list, T key) { jaroslav@597: if (list instanceof RandomAccess || list.size() jaroslav@597: int indexedBinarySearch(List> list, T key) jaroslav@597: { jaroslav@597: int low = 0; jaroslav@597: int high = list.size()-1; jaroslav@597: jaroslav@597: while (low <= high) { jaroslav@597: int mid = (low + high) >>> 1; jaroslav@597: Comparable midVal = list.get(mid); jaroslav@597: int cmp = midVal.compareTo(key); jaroslav@597: jaroslav@597: if (cmp < 0) jaroslav@597: low = mid + 1; jaroslav@597: else if (cmp > 0) jaroslav@597: high = mid - 1; jaroslav@597: else jaroslav@597: return mid; // key found jaroslav@597: } jaroslav@597: return -(low + 1); // key not found jaroslav@597: } jaroslav@597: jaroslav@597: private static jaroslav@597: int iteratorBinarySearch(List> list, T key) jaroslav@597: { jaroslav@597: int low = 0; jaroslav@597: int high = list.size()-1; jaroslav@597: ListIterator> i = list.listIterator(); jaroslav@597: jaroslav@597: while (low <= high) { jaroslav@597: int mid = (low + high) >>> 1; jaroslav@597: Comparable midVal = get(i, mid); jaroslav@597: int cmp = midVal.compareTo(key); jaroslav@597: jaroslav@597: if (cmp < 0) jaroslav@597: low = mid + 1; jaroslav@597: else if (cmp > 0) jaroslav@597: high = mid - 1; jaroslav@597: else jaroslav@597: return mid; // key found jaroslav@597: } jaroslav@597: return -(low + 1); // key not found jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Gets the ith element from the given list by repositioning the specified jaroslav@597: * list listIterator. jaroslav@597: */ jaroslav@597: private static T get(ListIterator i, int index) { jaroslav@597: T obj = null; jaroslav@597: int pos = i.nextIndex(); jaroslav@597: if (pos <= index) { jaroslav@597: do { jaroslav@597: obj = i.next(); jaroslav@597: } while (pos++ < index); jaroslav@597: } else { jaroslav@597: do { jaroslav@597: obj = i.previous(); jaroslav@597: } while (--pos > index); jaroslav@597: } jaroslav@597: return obj; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Searches the specified list for the specified object using the binary jaroslav@597: * search algorithm. The list must be sorted into ascending order jaroslav@597: * according to the specified comparator (as by the jaroslav@597: * {@link #sort(List, Comparator) sort(List, Comparator)} jaroslav@597: * method), prior to making this call. If it is jaroslav@597: * not sorted, the results are undefined. If the list contains multiple jaroslav@597: * elements equal to the specified object, there is no guarantee which one jaroslav@597: * will be found. jaroslav@597: * jaroslav@597: *

This method runs in log(n) time for a "random access" list (which jaroslav@597: * provides near-constant-time positional access). If the specified list jaroslav@597: * does not implement the {@link RandomAccess} interface and is large, jaroslav@597: * this method will do an iterator-based binary search that performs jaroslav@597: * O(n) link traversals and O(log n) element comparisons. jaroslav@597: * jaroslav@597: * @param list the list to be searched. jaroslav@597: * @param key the key to be searched for. jaroslav@597: * @param c the comparator by which the list is ordered. jaroslav@597: * A null value indicates that the elements' jaroslav@597: * {@linkplain Comparable natural ordering} should be used. jaroslav@597: * @return the index of the search key, if it is contained in the list; jaroslav@597: * otherwise, (-(insertion point) - 1). The jaroslav@597: * insertion point is defined as the point at which the jaroslav@597: * key would be inserted into the list: the index of the first jaroslav@597: * element greater than the key, or list.size() if all jaroslav@597: * elements in the list are less than the specified key. Note jaroslav@597: * that this guarantees that the return value will be >= 0 if jaroslav@597: * and only if the key is found. jaroslav@597: * @throws ClassCastException if the list contains elements that are not jaroslav@597: * mutually comparable using the specified comparator, jaroslav@597: * or the search key is not mutually comparable with the jaroslav@597: * elements of the list using this comparator. jaroslav@597: */ jaroslav@597: public static int binarySearch(List list, T key, Comparator c) { jaroslav@597: if (c==null) jaroslav@597: return binarySearch((List) list, key); jaroslav@597: jaroslav@597: if (list instanceof RandomAccess || list.size() int indexedBinarySearch(List l, T key, Comparator c) { jaroslav@597: int low = 0; jaroslav@597: int high = l.size()-1; jaroslav@597: jaroslav@597: while (low <= high) { jaroslav@597: int mid = (low + high) >>> 1; jaroslav@597: T midVal = l.get(mid); jaroslav@597: int cmp = c.compare(midVal, key); jaroslav@597: jaroslav@597: if (cmp < 0) jaroslav@597: low = mid + 1; jaroslav@597: else if (cmp > 0) jaroslav@597: high = mid - 1; jaroslav@597: else jaroslav@597: return mid; // key found jaroslav@597: } jaroslav@597: return -(low + 1); // key not found jaroslav@597: } jaroslav@597: jaroslav@597: private static int iteratorBinarySearch(List l, T key, Comparator c) { jaroslav@597: int low = 0; jaroslav@597: int high = l.size()-1; jaroslav@597: ListIterator i = l.listIterator(); jaroslav@597: jaroslav@597: while (low <= high) { jaroslav@597: int mid = (low + high) >>> 1; jaroslav@597: T midVal = get(i, mid); jaroslav@597: int cmp = c.compare(midVal, key); jaroslav@597: jaroslav@597: if (cmp < 0) jaroslav@597: low = mid + 1; jaroslav@597: else if (cmp > 0) jaroslav@597: high = mid - 1; jaroslav@597: else jaroslav@597: return mid; // key found jaroslav@597: } jaroslav@597: return -(low + 1); // key not found jaroslav@597: } jaroslav@597: jaroslav@597: private interface SelfComparable extends Comparable {} jaroslav@597: jaroslav@597: jaroslav@597: /** jaroslav@597: * Reverses the order of the elements in the specified list.

jaroslav@597: * jaroslav@597: * This method runs in linear time. jaroslav@597: * jaroslav@597: * @param list the list whose elements are to be reversed. jaroslav@597: * @throws UnsupportedOperationException if the specified list or jaroslav@597: * its list-iterator does not support the set operation. jaroslav@597: */ jaroslav@597: public static void reverse(List list) { jaroslav@597: int size = list.size(); jaroslav@597: if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) { jaroslav@597: for (int i=0, mid=size>>1, j=size-1; i>1; i jaroslav@597: * jaroslav@597: * The hedge "approximately" is used in the foregoing description because jaroslav@597: * default source of randomness is only approximately an unbiased source jaroslav@597: * of independently chosen bits. If it were a perfect source of randomly jaroslav@597: * chosen bits, then the algorithm would choose permutations with perfect jaroslav@597: * uniformity.

jaroslav@597: * jaroslav@597: * This implementation traverses the list backwards, from the last element jaroslav@597: * up to the second, repeatedly swapping a randomly selected element into jaroslav@597: * the "current position". Elements are randomly selected from the jaroslav@597: * portion of the list that runs from the first element to the current jaroslav@597: * position, inclusive.

jaroslav@597: * jaroslav@597: * This method runs in linear time. If the specified list does not jaroslav@597: * implement the {@link RandomAccess} interface and is large, this jaroslav@597: * implementation dumps the specified list into an array before shuffling jaroslav@597: * it, and dumps the shuffled array back into the list. This avoids the jaroslav@597: * quadratic behavior that would result from shuffling a "sequential jaroslav@597: * access" list in place. jaroslav@597: * jaroslav@597: * @param list the list to be shuffled. jaroslav@597: * @throws UnsupportedOperationException if the specified list or jaroslav@597: * its list-iterator does not support the set operation. jaroslav@597: */ jaroslav@597: public static void shuffle(List list) { jaroslav@597: Random rnd = r; jaroslav@597: if (rnd == null) jaroslav@597: r = rnd = new Random(); jaroslav@597: shuffle(list, rnd); jaroslav@597: } jaroslav@597: private static Random r; jaroslav@597: jaroslav@597: /** jaroslav@597: * Randomly permute the specified list using the specified source of jaroslav@597: * randomness. All permutations occur with equal likelihood jaroslav@597: * assuming that the source of randomness is fair.

jaroslav@597: * jaroslav@597: * This implementation traverses the list backwards, from the last element jaroslav@597: * up to the second, repeatedly swapping a randomly selected element into jaroslav@597: * the "current position". Elements are randomly selected from the jaroslav@597: * portion of the list that runs from the first element to the current jaroslav@597: * position, inclusive.

jaroslav@597: * jaroslav@597: * This method runs in linear time. If the specified list does not jaroslav@597: * implement the {@link RandomAccess} interface and is large, this jaroslav@597: * implementation dumps the specified list into an array before shuffling jaroslav@597: * it, and dumps the shuffled array back into the list. This avoids the jaroslav@597: * quadratic behavior that would result from shuffling a "sequential jaroslav@597: * access" list in place. jaroslav@597: * jaroslav@597: * @param list the list to be shuffled. jaroslav@597: * @param rnd the source of randomness to use to shuffle the list. jaroslav@597: * @throws UnsupportedOperationException if the specified list or its jaroslav@597: * list-iterator does not support the set operation. jaroslav@597: */ jaroslav@597: public static void shuffle(List list, Random rnd) { jaroslav@597: int size = list.size(); jaroslav@597: if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) { jaroslav@597: for (int i=size; i>1; i--) jaroslav@597: swap(list, i-1, rnd.nextInt(i)); jaroslav@597: } else { jaroslav@597: Object arr[] = list.toArray(); jaroslav@597: jaroslav@597: // Shuffle array jaroslav@597: for (int i=size; i>1; i--) jaroslav@597: swap(arr, i-1, rnd.nextInt(i)); jaroslav@597: jaroslav@597: // Dump array back into list jaroslav@597: ListIterator it = list.listIterator(); jaroslav@597: for (int i=0; ii or j jaroslav@597: * is out of range (i < 0 || i >= list.size() jaroslav@597: * || j < 0 || j >= list.size()). jaroslav@597: * @since 1.4 jaroslav@597: */ jaroslav@597: public static void swap(List list, int i, int j) { jaroslav@597: final List l = list; jaroslav@597: l.set(i, l.set(j, l.get(i))); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Swaps the two specified elements in the specified array. jaroslav@597: */ jaroslav@597: private static void swap(Object[] arr, int i, int j) { jaroslav@597: Object tmp = arr[i]; jaroslav@597: arr[i] = arr[j]; jaroslav@597: arr[j] = tmp; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Replaces all of the elements of the specified list with the specified jaroslav@597: * element.

jaroslav@597: * jaroslav@597: * This method runs in linear time. jaroslav@597: * jaroslav@597: * @param list the list to be filled with the specified element. jaroslav@597: * @param obj The element with which to fill the specified list. jaroslav@597: * @throws UnsupportedOperationException if the specified list or its jaroslav@597: * list-iterator does not support the set operation. jaroslav@597: */ jaroslav@597: public static void fill(List list, T obj) { jaroslav@597: int size = list.size(); jaroslav@597: jaroslav@597: if (size < FILL_THRESHOLD || list instanceof RandomAccess) { jaroslav@597: for (int i=0; i itr = list.listIterator(); jaroslav@597: for (int i=0; i jaroslav@597: * jaroslav@597: * This method runs in linear time. jaroslav@597: * jaroslav@597: * @param dest The destination list. jaroslav@597: * @param src The source list. jaroslav@597: * @throws IndexOutOfBoundsException if the destination list is too small jaroslav@597: * to contain the entire source List. jaroslav@597: * @throws UnsupportedOperationException if the destination list's jaroslav@597: * list-iterator does not support the set operation. jaroslav@597: */ jaroslav@597: public static void copy(List dest, List src) { jaroslav@597: int srcSize = src.size(); jaroslav@597: if (srcSize > dest.size()) jaroslav@597: throw new IndexOutOfBoundsException("Source does not fit in dest"); jaroslav@597: jaroslav@597: if (srcSize < COPY_THRESHOLD || jaroslav@597: (src instanceof RandomAccess && dest instanceof RandomAccess)) { jaroslav@597: for (int i=0; i di=dest.listIterator(); jaroslav@597: ListIterator si=src.listIterator(); jaroslav@597: for (int i=0; inatural ordering of its elements. All elements in the jaroslav@597: * collection must implement the Comparable interface. jaroslav@597: * Furthermore, all elements in the collection must be mutually jaroslav@597: * comparable (that is, e1.compareTo(e2) must not throw a jaroslav@597: * ClassCastException for any elements e1 and jaroslav@597: * e2 in the collection).

jaroslav@597: * jaroslav@597: * This method iterates over the entire collection, hence it requires jaroslav@597: * time proportional to the size of the collection. jaroslav@597: * jaroslav@597: * @param coll the collection whose minimum element is to be determined. jaroslav@597: * @return the minimum element of the given collection, according jaroslav@597: * to the natural ordering of its elements. jaroslav@597: * @throws ClassCastException if the collection contains elements that are jaroslav@597: * not mutually comparable (for example, strings and jaroslav@597: * integers). jaroslav@597: * @throws NoSuchElementException if the collection is empty. jaroslav@597: * @see Comparable jaroslav@597: */ jaroslav@597: public static > T min(Collection coll) { jaroslav@597: Iterator i = coll.iterator(); jaroslav@597: T candidate = i.next(); jaroslav@597: jaroslav@597: while (i.hasNext()) { jaroslav@597: T next = i.next(); jaroslav@597: if (next.compareTo(candidate) < 0) jaroslav@597: candidate = next; jaroslav@597: } jaroslav@597: return candidate; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the minimum element of the given collection, according to the jaroslav@597: * order induced by the specified comparator. All elements in the jaroslav@597: * collection must be mutually comparable by the specified jaroslav@597: * comparator (that is, comp.compare(e1, e2) must not throw a jaroslav@597: * ClassCastException for any elements e1 and jaroslav@597: * e2 in the collection).

jaroslav@597: * jaroslav@597: * This method iterates over the entire collection, hence it requires jaroslav@597: * time proportional to the size of the collection. jaroslav@597: * jaroslav@597: * @param coll the collection whose minimum element is to be determined. jaroslav@597: * @param comp the comparator with which to determine the minimum element. jaroslav@597: * A null value indicates that the elements' natural jaroslav@597: * ordering should be used. jaroslav@597: * @return the minimum element of the given collection, according jaroslav@597: * to the specified comparator. jaroslav@597: * @throws ClassCastException if the collection contains elements that are jaroslav@597: * not mutually comparable using the specified comparator. jaroslav@597: * @throws NoSuchElementException if the collection is empty. jaroslav@597: * @see Comparable jaroslav@597: */ jaroslav@597: public static T min(Collection coll, Comparator comp) { jaroslav@597: if (comp==null) jaroslav@597: return (T)min((Collection) (Collection) coll); jaroslav@597: jaroslav@597: Iterator i = coll.iterator(); jaroslav@597: T candidate = i.next(); jaroslav@597: jaroslav@597: while (i.hasNext()) { jaroslav@597: T next = i.next(); jaroslav@597: if (comp.compare(next, candidate) < 0) jaroslav@597: candidate = next; jaroslav@597: } jaroslav@597: return candidate; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the maximum element of the given collection, according to the jaroslav@597: * natural ordering of its elements. All elements in the jaroslav@597: * collection must implement the Comparable interface. jaroslav@597: * Furthermore, all elements in the collection must be mutually jaroslav@597: * comparable (that is, e1.compareTo(e2) must not throw a jaroslav@597: * ClassCastException for any elements e1 and jaroslav@597: * e2 in the collection).

jaroslav@597: * jaroslav@597: * This method iterates over the entire collection, hence it requires jaroslav@597: * time proportional to the size of the collection. jaroslav@597: * jaroslav@597: * @param coll the collection whose maximum element is to be determined. jaroslav@597: * @return the maximum element of the given collection, according jaroslav@597: * to the natural ordering of its elements. jaroslav@597: * @throws ClassCastException if the collection contains elements that are jaroslav@597: * not mutually comparable (for example, strings and jaroslav@597: * integers). jaroslav@597: * @throws NoSuchElementException if the collection is empty. jaroslav@597: * @see Comparable jaroslav@597: */ jaroslav@597: public static > T max(Collection coll) { jaroslav@597: Iterator i = coll.iterator(); jaroslav@597: T candidate = i.next(); jaroslav@597: jaroslav@597: while (i.hasNext()) { jaroslav@597: T next = i.next(); jaroslav@597: if (next.compareTo(candidate) > 0) jaroslav@597: candidate = next; jaroslav@597: } jaroslav@597: return candidate; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the maximum element of the given collection, according to the jaroslav@597: * order induced by the specified comparator. All elements in the jaroslav@597: * collection must be mutually comparable by the specified jaroslav@597: * comparator (that is, comp.compare(e1, e2) must not throw a jaroslav@597: * ClassCastException for any elements e1 and jaroslav@597: * e2 in the collection).

jaroslav@597: * jaroslav@597: * This method iterates over the entire collection, hence it requires jaroslav@597: * time proportional to the size of the collection. jaroslav@597: * jaroslav@597: * @param coll the collection whose maximum element is to be determined. jaroslav@597: * @param comp the comparator with which to determine the maximum element. jaroslav@597: * A null value indicates that the elements' natural jaroslav@597: * ordering should be used. jaroslav@597: * @return the maximum element of the given collection, according jaroslav@597: * to the specified comparator. jaroslav@597: * @throws ClassCastException if the collection contains elements that are jaroslav@597: * not mutually comparable using the specified comparator. jaroslav@597: * @throws NoSuchElementException if the collection is empty. jaroslav@597: * @see Comparable jaroslav@597: */ jaroslav@597: public static T max(Collection coll, Comparator comp) { jaroslav@597: if (comp==null) jaroslav@597: return (T)max((Collection) (Collection) coll); jaroslav@597: jaroslav@597: Iterator i = coll.iterator(); jaroslav@597: T candidate = i.next(); jaroslav@597: jaroslav@597: while (i.hasNext()) { jaroslav@597: T next = i.next(); jaroslav@597: if (comp.compare(next, candidate) > 0) jaroslav@597: candidate = next; jaroslav@597: } jaroslav@597: return candidate; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Rotates the elements in the specified list by the specified distance. jaroslav@597: * After calling this method, the element at index i will be jaroslav@597: * the element previously at index (i - distance) mod jaroslav@597: * list.size(), for all values of i between 0 jaroslav@597: * and list.size()-1, inclusive. (This method has no effect on jaroslav@597: * the size of the list.) jaroslav@597: * jaroslav@597: *

For example, suppose list comprises [t, a, n, k, s]. jaroslav@597: * After invoking Collections.rotate(list, 1) (or jaroslav@597: * Collections.rotate(list, -4)), list will comprise jaroslav@597: * [s, t, a, n, k]. jaroslav@597: * jaroslav@597: *

Note that this method can usefully be applied to sublists to jaroslav@597: * move one or more elements within a list while preserving the jaroslav@597: * order of the remaining elements. For example, the following idiom jaroslav@597: * moves the element at index j forward to position jaroslav@597: * k (which must be greater than or equal to j): jaroslav@597: *

jaroslav@597:      *     Collections.rotate(list.subList(j, k+1), -1);
jaroslav@597:      * 
jaroslav@597: * To make this concrete, suppose list comprises jaroslav@597: * [a, b, c, d, e]. To move the element at index 1 jaroslav@597: * (b) forward two positions, perform the following invocation: jaroslav@597: *
jaroslav@597:      *     Collections.rotate(l.subList(1, 4), -1);
jaroslav@597:      * 
jaroslav@597: * The resulting list is [a, c, d, b, e]. jaroslav@597: * jaroslav@597: *

To move more than one element forward, increase the absolute value jaroslav@597: * of the rotation distance. To move elements backward, use a positive jaroslav@597: * shift distance. jaroslav@597: * jaroslav@597: *

If the specified list is small or implements the {@link jaroslav@597: * RandomAccess} interface, this implementation exchanges the first jaroslav@597: * element into the location it should go, and then repeatedly exchanges jaroslav@597: * the displaced element into the location it should go until a displaced jaroslav@597: * element is swapped into the first element. If necessary, the process jaroslav@597: * is repeated on the second and successive elements, until the rotation jaroslav@597: * is complete. If the specified list is large and doesn't implement the jaroslav@597: * RandomAccess interface, this implementation breaks the jaroslav@597: * list into two sublist views around index -distance mod size. jaroslav@597: * Then the {@link #reverse(List)} method is invoked on each sublist view, jaroslav@597: * and finally it is invoked on the entire list. For a more complete jaroslav@597: * description of both algorithms, see Section 2.3 of Jon Bentley's jaroslav@597: * Programming Pearls (Addison-Wesley, 1986). jaroslav@597: * jaroslav@597: * @param list the list to be rotated. jaroslav@597: * @param distance the distance to rotate the list. There are no jaroslav@597: * constraints on this value; it may be zero, negative, or jaroslav@597: * greater than list.size(). jaroslav@597: * @throws UnsupportedOperationException if the specified list or jaroslav@597: * its list-iterator does not support the set operation. jaroslav@597: * @since 1.4 jaroslav@597: */ jaroslav@597: public static void rotate(List list, int distance) { jaroslav@597: if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD) jaroslav@597: rotate1(list, distance); jaroslav@597: else jaroslav@597: rotate2(list, distance); jaroslav@597: } jaroslav@597: jaroslav@597: private static void rotate1(List list, int distance) { jaroslav@597: int size = list.size(); jaroslav@597: if (size == 0) jaroslav@597: return; jaroslav@597: distance = distance % size; jaroslav@597: if (distance < 0) jaroslav@597: distance += size; jaroslav@597: if (distance == 0) jaroslav@597: return; jaroslav@597: jaroslav@597: for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) { jaroslav@597: T displaced = list.get(cycleStart); jaroslav@597: int i = cycleStart; jaroslav@597: do { jaroslav@597: i += distance; jaroslav@597: if (i >= size) jaroslav@597: i -= size; jaroslav@597: displaced = list.set(i, displaced); jaroslav@597: nMoved ++; jaroslav@597: } while (i != cycleStart); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: private static void rotate2(List list, int distance) { jaroslav@597: int size = list.size(); jaroslav@597: if (size == 0) jaroslav@597: return; jaroslav@597: int mid = -distance % size; jaroslav@597: if (mid < 0) jaroslav@597: mid += size; jaroslav@597: if (mid == 0) jaroslav@597: return; jaroslav@597: jaroslav@597: reverse(list.subList(0, mid)); jaroslav@597: reverse(list.subList(mid, size)); jaroslav@597: reverse(list); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Replaces all occurrences of one specified value in a list with another. jaroslav@597: * More formally, replaces with newVal each element e jaroslav@597: * in list such that jaroslav@597: * (oldVal==null ? e==null : oldVal.equals(e)). jaroslav@597: * (This method has no effect on the size of the list.) jaroslav@597: * jaroslav@597: * @param list the list in which replacement is to occur. jaroslav@597: * @param oldVal the old value to be replaced. jaroslav@597: * @param newVal the new value with which oldVal is to be jaroslav@597: * replaced. jaroslav@597: * @return true if list contained one or more elements jaroslav@597: * e such that jaroslav@597: * (oldVal==null ? e==null : oldVal.equals(e)). jaroslav@597: * @throws UnsupportedOperationException if the specified list or jaroslav@597: * its list-iterator does not support the set operation. jaroslav@597: * @since 1.4 jaroslav@597: */ jaroslav@597: public static boolean replaceAll(List list, T oldVal, T newVal) { jaroslav@597: boolean result = false; jaroslav@597: int size = list.size(); jaroslav@597: if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) { jaroslav@597: if (oldVal==null) { jaroslav@597: for (int i=0; i itr=list.listIterator(); jaroslav@597: if (oldVal==null) { jaroslav@597: for (int i=0; ii jaroslav@597: * such that source.subList(i, i+target.size()).equals(target), jaroslav@597: * or -1 if there is no such index. (Returns -1 if jaroslav@597: * target.size() > source.size().) jaroslav@597: * jaroslav@597: *

This implementation uses the "brute force" technique of scanning jaroslav@597: * over the source list, looking for a match with the target at each jaroslav@597: * location in turn. jaroslav@597: * jaroslav@597: * @param source the list in which to search for the first occurrence jaroslav@597: * of target. jaroslav@597: * @param target the list to search for as a subList of source. jaroslav@597: * @return the starting position of the first occurrence of the specified jaroslav@597: * target list within the specified source list, or -1 if there jaroslav@597: * is no such occurrence. jaroslav@597: * @since 1.4 jaroslav@597: */ jaroslav@597: public static int indexOfSubList(List source, List target) { jaroslav@597: int sourceSize = source.size(); jaroslav@597: int targetSize = target.size(); jaroslav@597: int maxCandidate = sourceSize - targetSize; jaroslav@597: jaroslav@597: if (sourceSize < INDEXOFSUBLIST_THRESHOLD || jaroslav@597: (source instanceof RandomAccess&&target instanceof RandomAccess)) { jaroslav@597: nextCand: jaroslav@597: for (int candidate = 0; candidate <= maxCandidate; candidate++) { jaroslav@597: for (int i=0, j=candidate; i si = source.listIterator(); jaroslav@597: nextCand: jaroslav@597: for (int candidate = 0; candidate <= maxCandidate; candidate++) { jaroslav@597: ListIterator ti = target.listIterator(); jaroslav@597: for (int i=0; ii jaroslav@597: * such that source.subList(i, i+target.size()).equals(target), jaroslav@597: * or -1 if there is no such index. (Returns -1 if jaroslav@597: * target.size() > source.size().) jaroslav@597: * jaroslav@597: *

This implementation uses the "brute force" technique of iterating jaroslav@597: * over the source list, looking for a match with the target at each jaroslav@597: * location in turn. jaroslav@597: * jaroslav@597: * @param source the list in which to search for the last occurrence jaroslav@597: * of target. jaroslav@597: * @param target the list to search for as a subList of source. jaroslav@597: * @return the starting position of the last occurrence of the specified jaroslav@597: * target list within the specified source list, or -1 if there jaroslav@597: * is no such occurrence. jaroslav@597: * @since 1.4 jaroslav@597: */ jaroslav@597: public static int lastIndexOfSubList(List source, List target) { jaroslav@597: int sourceSize = source.size(); jaroslav@597: int targetSize = target.size(); jaroslav@597: int maxCandidate = sourceSize - targetSize; jaroslav@597: jaroslav@597: if (sourceSize < INDEXOFSUBLIST_THRESHOLD || jaroslav@597: source instanceof RandomAccess) { // Index access version jaroslav@597: nextCand: jaroslav@597: for (int candidate = maxCandidate; candidate >= 0; candidate--) { jaroslav@597: for (int i=0, j=candidate; i si = source.listIterator(maxCandidate); jaroslav@597: nextCand: jaroslav@597: for (int candidate = maxCandidate; candidate >= 0; candidate--) { jaroslav@597: ListIterator ti = target.listIterator(); jaroslav@597: for (int i=0; iUnsupportedOperationException.

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

jaroslav@597: * jaroslav@597: * The returned collection will be serializable if the specified collection jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: * @param c the collection for which an unmodifiable view is to be jaroslav@597: * returned. jaroslav@597: * @return an unmodifiable view of the specified collection. jaroslav@597: */ jaroslav@597: public static Collection unmodifiableCollection(Collection c) { jaroslav@597: return new UnmodifiableCollection<>(c); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableCollection implements Collection, Serializable { jaroslav@597: private static final long serialVersionUID = 1820017752578914078L; jaroslav@597: jaroslav@597: final Collection c; jaroslav@597: jaroslav@597: UnmodifiableCollection(Collection c) { jaroslav@597: if (c==null) jaroslav@597: throw new NullPointerException(); jaroslav@597: this.c = c; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() {return c.size();} jaroslav@597: public boolean isEmpty() {return c.isEmpty();} jaroslav@597: public boolean contains(Object o) {return c.contains(o);} jaroslav@597: public Object[] toArray() {return c.toArray();} jaroslav@597: public T[] toArray(T[] a) {return c.toArray(a);} jaroslav@597: public String toString() {return c.toString();} jaroslav@597: jaroslav@597: public Iterator iterator() { jaroslav@597: return new Iterator() { jaroslav@597: private final Iterator i = c.iterator(); jaroslav@597: jaroslav@597: public boolean hasNext() {return i.hasNext();} jaroslav@597: public E next() {return i.next();} jaroslav@597: public void remove() { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean add(E e) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public boolean remove(Object o) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean containsAll(Collection coll) { jaroslav@597: return c.containsAll(coll); jaroslav@597: } jaroslav@597: public boolean addAll(Collection coll) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public boolean removeAll(Collection coll) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public boolean retainAll(Collection coll) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public void clear() { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an unmodifiable view of the specified set. This method allows jaroslav@597: * modules to provide users with "read-only" access to internal sets. jaroslav@597: * Query operations on the returned set "read through" to the specified jaroslav@597: * set, and attempts to modify the returned set, whether direct or via its jaroslav@597: * iterator, result in an UnsupportedOperationException.

jaroslav@597: * jaroslav@597: * The returned set will be serializable if the specified set jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: * @param s the set for which an unmodifiable view is to be returned. jaroslav@597: * @return an unmodifiable view of the specified set. jaroslav@597: */ jaroslav@597: public static Set unmodifiableSet(Set s) { jaroslav@597: return new UnmodifiableSet<>(s); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableSet extends UnmodifiableCollection jaroslav@597: implements Set, Serializable { jaroslav@597: private static final long serialVersionUID = -9215047833775013803L; jaroslav@597: jaroslav@597: UnmodifiableSet(Set s) {super(s);} jaroslav@597: public boolean equals(Object o) {return o == this || c.equals(o);} jaroslav@597: public int hashCode() {return c.hashCode();} jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an unmodifiable view of the specified sorted set. This method jaroslav@597: * allows modules to provide users with "read-only" access to internal jaroslav@597: * sorted sets. Query operations on the returned sorted set "read jaroslav@597: * through" to the specified sorted set. Attempts to modify the returned jaroslav@597: * sorted set, whether direct, via its iterator, or via its jaroslav@597: * subSet, headSet, or tailSet views, result in jaroslav@597: * an UnsupportedOperationException.

jaroslav@597: * jaroslav@597: * The returned sorted set will be serializable if the specified sorted set jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: * @param s the sorted set for which an unmodifiable view is to be jaroslav@597: * returned. jaroslav@597: * @return an unmodifiable view of the specified sorted set. jaroslav@597: */ jaroslav@597: public static SortedSet unmodifiableSortedSet(SortedSet s) { jaroslav@597: return new UnmodifiableSortedSet<>(s); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableSortedSet jaroslav@597: extends UnmodifiableSet jaroslav@597: implements SortedSet, Serializable { jaroslav@597: private static final long serialVersionUID = -4929149591599911165L; jaroslav@597: private final SortedSet ss; jaroslav@597: jaroslav@597: UnmodifiableSortedSet(SortedSet s) {super(s); ss = s;} jaroslav@597: jaroslav@597: public Comparator comparator() {return ss.comparator();} jaroslav@597: jaroslav@597: public SortedSet subSet(E fromElement, E toElement) { jaroslav@597: return new UnmodifiableSortedSet<>(ss.subSet(fromElement,toElement)); jaroslav@597: } jaroslav@597: public SortedSet headSet(E toElement) { jaroslav@597: return new UnmodifiableSortedSet<>(ss.headSet(toElement)); jaroslav@597: } jaroslav@597: public SortedSet tailSet(E fromElement) { jaroslav@597: return new UnmodifiableSortedSet<>(ss.tailSet(fromElement)); jaroslav@597: } jaroslav@597: jaroslav@597: public E first() {return ss.first();} jaroslav@597: public E last() {return ss.last();} jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an unmodifiable view of the specified list. This method allows jaroslav@597: * modules to provide users with "read-only" access to internal jaroslav@597: * lists. Query operations on the returned list "read through" to the jaroslav@597: * specified list, and attempts to modify the returned list, whether jaroslav@597: * direct or via its iterator, result in an jaroslav@597: * UnsupportedOperationException.

jaroslav@597: * jaroslav@597: * The returned list will be serializable if the specified list jaroslav@597: * is serializable. Similarly, the returned list will implement jaroslav@597: * {@link RandomAccess} if the specified list does. jaroslav@597: * jaroslav@597: * @param list the list for which an unmodifiable view is to be returned. jaroslav@597: * @return an unmodifiable view of the specified list. jaroslav@597: */ jaroslav@597: public static List unmodifiableList(List list) { jaroslav@597: return (list instanceof RandomAccess ? jaroslav@597: new UnmodifiableRandomAccessList<>(list) : jaroslav@597: new UnmodifiableList<>(list)); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableList extends UnmodifiableCollection jaroslav@597: implements List { jaroslav@597: private static final long serialVersionUID = -283967356065247728L; jaroslav@597: final List list; jaroslav@597: jaroslav@597: UnmodifiableList(List list) { jaroslav@597: super(list); jaroslav@597: this.list = list; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) {return o == this || list.equals(o);} jaroslav@597: public int hashCode() {return list.hashCode();} jaroslav@597: jaroslav@597: public E get(int index) {return list.get(index);} jaroslav@597: public E set(int index, E element) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public void add(int index, E element) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public E remove(int index) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public int indexOf(Object o) {return list.indexOf(o);} jaroslav@597: public int lastIndexOf(Object o) {return list.lastIndexOf(o);} jaroslav@597: public boolean addAll(int index, Collection c) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public ListIterator listIterator() {return listIterator(0);} jaroslav@597: jaroslav@597: public ListIterator listIterator(final int index) { jaroslav@597: return new ListIterator() { jaroslav@597: private final ListIterator i jaroslav@597: = list.listIterator(index); jaroslav@597: jaroslav@597: public boolean hasNext() {return i.hasNext();} jaroslav@597: public E next() {return i.next();} jaroslav@597: public boolean hasPrevious() {return i.hasPrevious();} jaroslav@597: public E previous() {return i.previous();} jaroslav@597: public int nextIndex() {return i.nextIndex();} jaroslav@597: public int previousIndex() {return i.previousIndex();} jaroslav@597: jaroslav@597: public void remove() { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public void set(E e) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public void add(E e) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: return new UnmodifiableList<>(list.subList(fromIndex, toIndex)); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * UnmodifiableRandomAccessList instances are serialized as jaroslav@597: * UnmodifiableList instances to allow them to be deserialized jaroslav@597: * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). jaroslav@597: * This method inverts the transformation. As a beneficial jaroslav@597: * side-effect, it also grafts the RandomAccess marker onto jaroslav@597: * UnmodifiableList instances that were serialized in pre-1.4 JREs. jaroslav@597: * jaroslav@597: * Note: Unfortunately, UnmodifiableRandomAccessList instances jaroslav@597: * serialized in 1.4.1 and deserialized in 1.4 will become jaroslav@597: * UnmodifiableList instances, as this method was missing in 1.4. jaroslav@597: */ jaroslav@597: private Object readResolve() { jaroslav@597: return (list instanceof RandomAccess jaroslav@597: ? new UnmodifiableRandomAccessList<>(list) jaroslav@597: : this); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableRandomAccessList extends UnmodifiableList jaroslav@597: implements RandomAccess jaroslav@597: { jaroslav@597: UnmodifiableRandomAccessList(List list) { jaroslav@597: super(list); jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: return new UnmodifiableRandomAccessList<>( jaroslav@597: list.subList(fromIndex, toIndex)); jaroslav@597: } jaroslav@597: jaroslav@597: private static final long serialVersionUID = -2542308836966382001L; jaroslav@597: jaroslav@597: /** jaroslav@597: * Allows instances to be deserialized in pre-1.4 JREs (which do jaroslav@597: * not have UnmodifiableRandomAccessList). UnmodifiableList has jaroslav@597: * a readResolve method that inverts this transformation upon jaroslav@597: * deserialization. jaroslav@597: */ jaroslav@597: private Object writeReplace() { jaroslav@597: return new UnmodifiableList<>(list); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an unmodifiable view of the specified map. This method jaroslav@597: * allows modules to provide users with "read-only" access to internal jaroslav@597: * maps. Query operations on the returned map "read through" jaroslav@597: * to the specified map, and attempts to modify the returned jaroslav@597: * map, whether direct or via its collection views, result in an jaroslav@597: * UnsupportedOperationException.

jaroslav@597: * jaroslav@597: * The returned map will be serializable if the specified map jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: * @param m the map for which an unmodifiable view is to be returned. jaroslav@597: * @return an unmodifiable view of the specified map. jaroslav@597: */ jaroslav@597: public static Map unmodifiableMap(Map m) { jaroslav@597: return new UnmodifiableMap<>(m); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class UnmodifiableMap implements Map, Serializable { jaroslav@597: private static final long serialVersionUID = -1034234728574286014L; jaroslav@597: jaroslav@597: private final Map m; jaroslav@597: jaroslav@597: UnmodifiableMap(Map m) { jaroslav@597: if (m==null) jaroslav@597: throw new NullPointerException(); jaroslav@597: this.m = m; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() {return m.size();} jaroslav@597: public boolean isEmpty() {return m.isEmpty();} jaroslav@597: public boolean containsKey(Object key) {return m.containsKey(key);} jaroslav@597: public boolean containsValue(Object val) {return m.containsValue(val);} jaroslav@597: public V get(Object key) {return m.get(key);} jaroslav@597: jaroslav@597: public V put(K key, V value) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public V remove(Object key) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public void putAll(Map m) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public void clear() { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: jaroslav@597: private transient Set keySet = null; jaroslav@597: private transient Set> entrySet = null; jaroslav@597: private transient Collection values = null; jaroslav@597: jaroslav@597: public Set keySet() { jaroslav@597: if (keySet==null) jaroslav@597: keySet = unmodifiableSet(m.keySet()); jaroslav@597: return keySet; jaroslav@597: } jaroslav@597: jaroslav@597: public Set> entrySet() { jaroslav@597: if (entrySet==null) jaroslav@597: entrySet = new UnmodifiableEntrySet<>(m.entrySet()); jaroslav@597: return entrySet; jaroslav@597: } jaroslav@597: jaroslav@597: public Collection values() { jaroslav@597: if (values==null) jaroslav@597: values = unmodifiableCollection(m.values()); jaroslav@597: return values; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) {return o == this || m.equals(o);} jaroslav@597: public int hashCode() {return m.hashCode();} jaroslav@597: public String toString() {return m.toString();} jaroslav@597: jaroslav@597: /** jaroslav@597: * We need this class in addition to UnmodifiableSet as jaroslav@597: * Map.Entries themselves permit modification of the backing Map jaroslav@597: * via their setValue operation. This class is subtle: there are jaroslav@597: * many possible attacks that must be thwarted. jaroslav@597: * jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableEntrySet jaroslav@597: extends UnmodifiableSet> { jaroslav@597: private static final long serialVersionUID = 7854390611657943733L; jaroslav@597: jaroslav@597: UnmodifiableEntrySet(Set> s) { jaroslav@597: super((Set)s); jaroslav@597: } jaroslav@597: public Iterator> iterator() { jaroslav@597: return new Iterator>() { jaroslav@597: private final Iterator> i = c.iterator(); jaroslav@597: jaroslav@597: public boolean hasNext() { jaroslav@597: return i.hasNext(); jaroslav@597: } jaroslav@597: public Map.Entry next() { jaroslav@597: return new UnmodifiableEntry<>(i.next()); jaroslav@597: } jaroslav@597: public void remove() { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: public Object[] toArray() { jaroslav@597: Object[] a = c.toArray(); jaroslav@597: for (int i=0; i((Map.Entry)a[i]); jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: // We don't pass a to c.toArray, to avoid window of jaroslav@597: // vulnerability wherein an unscrupulous multithreaded client jaroslav@597: // could get his hands on raw (unwrapped) Entries from c. jaroslav@597: Object[] arr = c.toArray(a.length==0 ? a : Arrays.copyOf(a, 0)); jaroslav@597: jaroslav@597: for (int i=0; i((Map.Entry)arr[i]); jaroslav@597: jaroslav@597: if (arr.length > a.length) jaroslav@597: return (T[])arr; jaroslav@597: jaroslav@597: System.arraycopy(arr, 0, a, 0, arr.length); jaroslav@597: if (a.length > arr.length) jaroslav@597: a[arr.length] = null; jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * This method is overridden to protect the backing set against jaroslav@597: * an object with a nefarious equals function that senses jaroslav@597: * that the equality-candidate is Map.Entry and calls its jaroslav@597: * setValue method. jaroslav@597: */ jaroslav@597: public boolean contains(Object o) { jaroslav@597: if (!(o instanceof Map.Entry)) jaroslav@597: return false; jaroslav@597: return c.contains( jaroslav@597: new UnmodifiableEntry<>((Map.Entry) o)); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * The next two methods are overridden to protect against jaroslav@597: * an unscrupulous List whose contains(Object o) method senses jaroslav@597: * when o is a Map.Entry, and calls o.setValue. jaroslav@597: */ jaroslav@597: public boolean containsAll(Collection coll) { jaroslav@597: for (Object e : coll) { jaroslav@597: if (!contains(e)) // Invokes safe contains() above jaroslav@597: return false; jaroslav@597: } jaroslav@597: return true; jaroslav@597: } jaroslav@597: public boolean equals(Object o) { jaroslav@597: if (o == this) jaroslav@597: return true; jaroslav@597: jaroslav@597: if (!(o instanceof Set)) jaroslav@597: return false; jaroslav@597: Set s = (Set) o; jaroslav@597: if (s.size() != c.size()) jaroslav@597: return false; jaroslav@597: return containsAll(s); // Invokes safe containsAll() above jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * This "wrapper class" serves two purposes: it prevents jaroslav@597: * the client from modifying the backing Map, by short-circuiting jaroslav@597: * the setValue method, and it protects the backing Map against jaroslav@597: * an ill-behaved Map.Entry that attempts to modify another jaroslav@597: * Map Entry when asked to perform an equality check. jaroslav@597: */ jaroslav@597: private static class UnmodifiableEntry implements Map.Entry { jaroslav@597: private Map.Entry e; jaroslav@597: jaroslav@597: UnmodifiableEntry(Map.Entry e) {this.e = e;} jaroslav@597: jaroslav@597: public K getKey() {return e.getKey();} jaroslav@597: public V getValue() {return e.getValue();} jaroslav@597: public V setValue(V value) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public int hashCode() {return e.hashCode();} jaroslav@597: public boolean equals(Object o) { jaroslav@597: if (!(o instanceof Map.Entry)) jaroslav@597: return false; jaroslav@597: Map.Entry t = (Map.Entry)o; jaroslav@597: return eq(e.getKey(), t.getKey()) && jaroslav@597: eq(e.getValue(), t.getValue()); jaroslav@597: } jaroslav@597: public String toString() {return e.toString();} jaroslav@597: } jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an unmodifiable view of the specified sorted map. This method jaroslav@597: * allows modules to provide users with "read-only" access to internal jaroslav@597: * sorted maps. Query operations on the returned sorted map "read through" jaroslav@597: * to the specified sorted map. Attempts to modify the returned jaroslav@597: * sorted map, whether direct, via its collection views, or via its jaroslav@597: * subMap, headMap, or tailMap views, result in jaroslav@597: * an UnsupportedOperationException.

jaroslav@597: * jaroslav@597: * The returned sorted map will be serializable if the specified sorted map jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: * @param m the sorted map for which an unmodifiable view is to be jaroslav@597: * returned. jaroslav@597: * @return an unmodifiable view of the specified sorted map. jaroslav@597: */ jaroslav@597: public static SortedMap unmodifiableSortedMap(SortedMap m) { jaroslav@597: return new UnmodifiableSortedMap<>(m); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class UnmodifiableSortedMap jaroslav@597: extends UnmodifiableMap jaroslav@597: implements SortedMap, Serializable { jaroslav@597: private static final long serialVersionUID = -8806743815996713206L; jaroslav@597: jaroslav@597: private final SortedMap sm; jaroslav@597: jaroslav@597: UnmodifiableSortedMap(SortedMap m) {super(m); sm = m;} jaroslav@597: jaroslav@597: public Comparator comparator() {return sm.comparator();} jaroslav@597: jaroslav@597: public SortedMap subMap(K fromKey, K toKey) { jaroslav@597: return new UnmodifiableSortedMap<>(sm.subMap(fromKey, toKey)); jaroslav@597: } jaroslav@597: public SortedMap headMap(K toKey) { jaroslav@597: return new UnmodifiableSortedMap<>(sm.headMap(toKey)); jaroslav@597: } jaroslav@597: public SortedMap tailMap(K fromKey) { jaroslav@597: return new UnmodifiableSortedMap<>(sm.tailMap(fromKey)); jaroslav@597: } jaroslav@597: jaroslav@597: public K firstKey() {return sm.firstKey();} jaroslav@597: public K lastKey() {return sm.lastKey();} jaroslav@597: } jaroslav@597: jaroslav@597: jaroslav@597: // Synch Wrappers jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a synchronized (thread-safe) collection backed by the specified jaroslav@597: * collection. In order to guarantee serial access, it is critical that jaroslav@597: * all access to the backing collection is accomplished jaroslav@597: * through the returned collection.

jaroslav@597: * jaroslav@597: * It is imperative that the user manually synchronize on the returned jaroslav@597: * collection when iterating over it: jaroslav@597: *

jaroslav@597:      *  Collection c = Collections.synchronizedCollection(myCollection);
jaroslav@597:      *     ...
jaroslav@597:      *  synchronized (c) {
jaroslav@597:      *      Iterator i = c.iterator(); // Must be in the synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *         foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * Failure to follow this advice may result in non-deterministic behavior. jaroslav@597: * jaroslav@597: *

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

jaroslav@597: * jaroslav@597: * The returned collection will be serializable if the specified collection jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: * @param c the collection to be "wrapped" in a synchronized collection. jaroslav@597: * @return a synchronized view of the specified collection. jaroslav@597: */ jaroslav@597: public static Collection synchronizedCollection(Collection c) { jaroslav@597: return new SynchronizedCollection<>(c); jaroslav@597: } jaroslav@597: jaroslav@597: static Collection synchronizedCollection(Collection c, Object mutex) { jaroslav@597: return new SynchronizedCollection<>(c, mutex); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class SynchronizedCollection implements Collection, Serializable { jaroslav@597: private static final long serialVersionUID = 3053995032091335093L; jaroslav@597: jaroslav@597: final Collection c; // Backing Collection jaroslav@597: final Object mutex; // Object on which to synchronize jaroslav@597: jaroslav@597: SynchronizedCollection(Collection c) { jaroslav@597: if (c==null) jaroslav@597: throw new NullPointerException(); jaroslav@597: this.c = c; jaroslav@597: mutex = this; jaroslav@597: } jaroslav@597: SynchronizedCollection(Collection c, Object mutex) { jaroslav@597: this.c = c; jaroslav@597: this.mutex = mutex; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() { jaroslav@597: synchronized (mutex) {return c.size();} jaroslav@597: } jaroslav@597: public boolean isEmpty() { jaroslav@597: synchronized (mutex) {return c.isEmpty();} jaroslav@597: } jaroslav@597: public boolean contains(Object o) { jaroslav@597: synchronized (mutex) {return c.contains(o);} jaroslav@597: } jaroslav@597: public Object[] toArray() { jaroslav@597: synchronized (mutex) {return c.toArray();} jaroslav@597: } jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: synchronized (mutex) {return c.toArray(a);} jaroslav@597: } jaroslav@597: jaroslav@597: public Iterator iterator() { jaroslav@597: return c.iterator(); // Must be manually synched by user! jaroslav@597: } jaroslav@597: jaroslav@597: public boolean add(E e) { jaroslav@597: synchronized (mutex) {return c.add(e);} jaroslav@597: } jaroslav@597: public boolean remove(Object o) { jaroslav@597: synchronized (mutex) {return c.remove(o);} jaroslav@597: } jaroslav@597: jaroslav@597: public boolean containsAll(Collection coll) { jaroslav@597: synchronized (mutex) {return c.containsAll(coll);} jaroslav@597: } jaroslav@597: public boolean addAll(Collection coll) { jaroslav@597: synchronized (mutex) {return c.addAll(coll);} jaroslav@597: } jaroslav@597: public boolean removeAll(Collection coll) { jaroslav@597: synchronized (mutex) {return c.removeAll(coll);} jaroslav@597: } jaroslav@597: public boolean retainAll(Collection coll) { jaroslav@597: synchronized (mutex) {return c.retainAll(coll);} jaroslav@597: } jaroslav@597: public void clear() { jaroslav@597: synchronized (mutex) {c.clear();} jaroslav@597: } jaroslav@597: public String toString() { jaroslav@597: synchronized (mutex) {return c.toString();} jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a synchronized (thread-safe) set backed by the specified jaroslav@597: * set. In order to guarantee serial access, it is critical that jaroslav@597: * all access to the backing set is accomplished jaroslav@597: * through the returned set.

jaroslav@597: * jaroslav@597: * It is imperative that the user manually synchronize on the returned jaroslav@597: * set when iterating over it: jaroslav@597: *

jaroslav@597:      *  Set s = Collections.synchronizedSet(new HashSet());
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (s) {
jaroslav@597:      *      Iterator i = s.iterator(); // Must be in the synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * Failure to follow this advice may result in non-deterministic behavior. jaroslav@597: * jaroslav@597: *

The returned set will be serializable if the specified set is jaroslav@597: * serializable. jaroslav@597: * jaroslav@597: * @param s the set to be "wrapped" in a synchronized set. jaroslav@597: * @return a synchronized view of the specified set. jaroslav@597: */ jaroslav@597: public static Set synchronizedSet(Set s) { jaroslav@597: return new SynchronizedSet<>(s); jaroslav@597: } jaroslav@597: jaroslav@597: static Set synchronizedSet(Set s, Object mutex) { jaroslav@597: return new SynchronizedSet<>(s, mutex); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class SynchronizedSet jaroslav@597: extends SynchronizedCollection jaroslav@597: implements Set { jaroslav@597: private static final long serialVersionUID = 487447009682186044L; jaroslav@597: jaroslav@597: SynchronizedSet(Set s) { jaroslav@597: super(s); jaroslav@597: } jaroslav@597: SynchronizedSet(Set s, Object mutex) { jaroslav@597: super(s, mutex); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: synchronized (mutex) {return c.equals(o);} jaroslav@597: } jaroslav@597: public int hashCode() { jaroslav@597: synchronized (mutex) {return c.hashCode();} jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a synchronized (thread-safe) sorted set backed by the specified jaroslav@597: * sorted set. In order to guarantee serial access, it is critical that jaroslav@597: * all access to the backing sorted set is accomplished jaroslav@597: * through the returned sorted set (or its views).

jaroslav@597: * jaroslav@597: * It is imperative that the user manually synchronize on the returned jaroslav@597: * sorted set when iterating over it or any of its subSet, jaroslav@597: * headSet, or tailSet views. jaroslav@597: *

jaroslav@597:      *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (s) {
jaroslav@597:      *      Iterator i = s.iterator(); // Must be in the synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * or: jaroslav@597: *
jaroslav@597:      *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
jaroslav@597:      *  SortedSet s2 = s.headSet(foo);
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (s) {  // Note: s, not s2!!!
jaroslav@597:      *      Iterator i = s2.iterator(); // Must be in the synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * Failure to follow this advice may result in non-deterministic behavior. jaroslav@597: * jaroslav@597: *

The returned sorted set will be serializable if the specified jaroslav@597: * sorted set is serializable. jaroslav@597: * jaroslav@597: * @param s the sorted set to be "wrapped" in a synchronized sorted set. jaroslav@597: * @return a synchronized view of the specified sorted set. jaroslav@597: */ jaroslav@597: public static SortedSet synchronizedSortedSet(SortedSet s) { jaroslav@597: return new SynchronizedSortedSet<>(s); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class SynchronizedSortedSet jaroslav@597: extends SynchronizedSet jaroslav@597: implements SortedSet jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 8695801310862127406L; jaroslav@597: jaroslav@597: private final SortedSet ss; jaroslav@597: jaroslav@597: SynchronizedSortedSet(SortedSet s) { jaroslav@597: super(s); jaroslav@597: ss = s; jaroslav@597: } jaroslav@597: SynchronizedSortedSet(SortedSet s, Object mutex) { jaroslav@597: super(s, mutex); jaroslav@597: ss = s; jaroslav@597: } jaroslav@597: jaroslav@597: public Comparator comparator() { jaroslav@597: synchronized (mutex) {return ss.comparator();} jaroslav@597: } jaroslav@597: jaroslav@597: public SortedSet subSet(E fromElement, E toElement) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedSortedSet<>( jaroslav@597: ss.subSet(fromElement, toElement), mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: public SortedSet headSet(E toElement) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: public SortedSet tailSet(E fromElement) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedSortedSet<>(ss.tailSet(fromElement),mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: public E first() { jaroslav@597: synchronized (mutex) {return ss.first();} jaroslav@597: } jaroslav@597: public E last() { jaroslav@597: synchronized (mutex) {return ss.last();} jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a synchronized (thread-safe) list backed by the specified jaroslav@597: * list. In order to guarantee serial access, it is critical that jaroslav@597: * all access to the backing list is accomplished jaroslav@597: * through the returned list.

jaroslav@597: * jaroslav@597: * It is imperative that the user manually synchronize on the returned jaroslav@597: * list when iterating over it: jaroslav@597: *

jaroslav@597:      *  List list = Collections.synchronizedList(new ArrayList());
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (list) {
jaroslav@597:      *      Iterator i = list.iterator(); // Must be in synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * Failure to follow this advice may result in non-deterministic behavior. jaroslav@597: * jaroslav@597: *

The returned list will be serializable if the specified list is jaroslav@597: * serializable. jaroslav@597: * jaroslav@597: * @param list the list to be "wrapped" in a synchronized list. jaroslav@597: * @return a synchronized view of the specified list. jaroslav@597: */ jaroslav@597: public static List synchronizedList(List list) { jaroslav@597: return (list instanceof RandomAccess ? jaroslav@597: new SynchronizedRandomAccessList<>(list) : jaroslav@597: new SynchronizedList<>(list)); jaroslav@597: } jaroslav@597: jaroslav@597: static List synchronizedList(List list, Object mutex) { jaroslav@597: return (list instanceof RandomAccess ? jaroslav@597: new SynchronizedRandomAccessList<>(list, mutex) : jaroslav@597: new SynchronizedList<>(list, mutex)); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class SynchronizedList jaroslav@597: extends SynchronizedCollection jaroslav@597: implements List { jaroslav@597: private static final long serialVersionUID = -7754090372962971524L; jaroslav@597: jaroslav@597: final List list; jaroslav@597: jaroslav@597: SynchronizedList(List list) { jaroslav@597: super(list); jaroslav@597: this.list = list; jaroslav@597: } jaroslav@597: SynchronizedList(List list, Object mutex) { jaroslav@597: super(list, mutex); jaroslav@597: this.list = list; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: synchronized (mutex) {return list.equals(o);} jaroslav@597: } jaroslav@597: public int hashCode() { jaroslav@597: synchronized (mutex) {return list.hashCode();} jaroslav@597: } jaroslav@597: jaroslav@597: public E get(int index) { jaroslav@597: synchronized (mutex) {return list.get(index);} jaroslav@597: } jaroslav@597: public E set(int index, E element) { jaroslav@597: synchronized (mutex) {return list.set(index, element);} jaroslav@597: } jaroslav@597: public void add(int index, E element) { jaroslav@597: synchronized (mutex) {list.add(index, element);} jaroslav@597: } jaroslav@597: public E remove(int index) { jaroslav@597: synchronized (mutex) {return list.remove(index);} jaroslav@597: } jaroslav@597: jaroslav@597: public int indexOf(Object o) { jaroslav@597: synchronized (mutex) {return list.indexOf(o);} jaroslav@597: } jaroslav@597: public int lastIndexOf(Object o) { jaroslav@597: synchronized (mutex) {return list.lastIndexOf(o);} jaroslav@597: } jaroslav@597: jaroslav@597: public boolean addAll(int index, Collection c) { jaroslav@597: synchronized (mutex) {return list.addAll(index, c);} jaroslav@597: } jaroslav@597: jaroslav@597: public ListIterator listIterator() { jaroslav@597: return list.listIterator(); // Must be manually synched by user jaroslav@597: } jaroslav@597: jaroslav@597: public ListIterator listIterator(int index) { jaroslav@597: return list.listIterator(index); // Must be manually synched by user jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedList<>(list.subList(fromIndex, toIndex), jaroslav@597: mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * SynchronizedRandomAccessList instances are serialized as jaroslav@597: * SynchronizedList instances to allow them to be deserialized jaroslav@597: * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). jaroslav@597: * This method inverts the transformation. As a beneficial jaroslav@597: * side-effect, it also grafts the RandomAccess marker onto jaroslav@597: * SynchronizedList instances that were serialized in pre-1.4 JREs. jaroslav@597: * jaroslav@597: * Note: Unfortunately, SynchronizedRandomAccessList instances jaroslav@597: * serialized in 1.4.1 and deserialized in 1.4 will become jaroslav@597: * SynchronizedList instances, as this method was missing in 1.4. jaroslav@597: */ jaroslav@597: private Object readResolve() { jaroslav@597: return (list instanceof RandomAccess jaroslav@597: ? new SynchronizedRandomAccessList<>(list) jaroslav@597: : this); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class SynchronizedRandomAccessList jaroslav@597: extends SynchronizedList jaroslav@597: implements RandomAccess { jaroslav@597: jaroslav@597: SynchronizedRandomAccessList(List list) { jaroslav@597: super(list); jaroslav@597: } jaroslav@597: jaroslav@597: SynchronizedRandomAccessList(List list, Object mutex) { jaroslav@597: super(list, mutex); jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedRandomAccessList<>( jaroslav@597: list.subList(fromIndex, toIndex), mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: private static final long serialVersionUID = 1530674583602358482L; jaroslav@597: jaroslav@597: /** jaroslav@597: * Allows instances to be deserialized in pre-1.4 JREs (which do jaroslav@597: * not have SynchronizedRandomAccessList). SynchronizedList has jaroslav@597: * a readResolve method that inverts this transformation upon jaroslav@597: * deserialization. jaroslav@597: */ jaroslav@597: private Object writeReplace() { jaroslav@597: return new SynchronizedList<>(list); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a synchronized (thread-safe) map backed by the specified jaroslav@597: * map. In order to guarantee serial access, it is critical that jaroslav@597: * all access to the backing map is accomplished jaroslav@597: * through the returned map.

jaroslav@597: * jaroslav@597: * It is imperative that the user manually synchronize on the returned jaroslav@597: * map when iterating over any of its collection views: jaroslav@597: *

jaroslav@597:      *  Map m = Collections.synchronizedMap(new HashMap());
jaroslav@597:      *      ...
jaroslav@597:      *  Set s = m.keySet();  // Needn't be in synchronized block
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (m) {  // Synchronizing on m, not s!
jaroslav@597:      *      Iterator i = s.iterator(); // Must be in synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * Failure to follow this advice may result in non-deterministic behavior. jaroslav@597: * jaroslav@597: *

The returned map will be serializable if the specified map is jaroslav@597: * serializable. jaroslav@597: * jaroslav@597: * @param m the map to be "wrapped" in a synchronized map. jaroslav@597: * @return a synchronized view of the specified map. jaroslav@597: */ jaroslav@597: public static Map synchronizedMap(Map m) { jaroslav@597: return new SynchronizedMap<>(m); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class SynchronizedMap jaroslav@597: implements Map, Serializable { jaroslav@597: private static final long serialVersionUID = 1978198479659022715L; jaroslav@597: jaroslav@597: private final Map m; // Backing Map jaroslav@597: final Object mutex; // Object on which to synchronize jaroslav@597: jaroslav@597: SynchronizedMap(Map m) { jaroslav@597: if (m==null) jaroslav@597: throw new NullPointerException(); jaroslav@597: this.m = m; jaroslav@597: mutex = this; jaroslav@597: } jaroslav@597: jaroslav@597: SynchronizedMap(Map m, Object mutex) { jaroslav@597: this.m = m; jaroslav@597: this.mutex = mutex; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() { jaroslav@597: synchronized (mutex) {return m.size();} jaroslav@597: } jaroslav@597: public boolean isEmpty() { jaroslav@597: synchronized (mutex) {return m.isEmpty();} jaroslav@597: } jaroslav@597: public boolean containsKey(Object key) { jaroslav@597: synchronized (mutex) {return m.containsKey(key);} jaroslav@597: } jaroslav@597: public boolean containsValue(Object value) { jaroslav@597: synchronized (mutex) {return m.containsValue(value);} jaroslav@597: } jaroslav@597: public V get(Object key) { jaroslav@597: synchronized (mutex) {return m.get(key);} jaroslav@597: } jaroslav@597: jaroslav@597: public V put(K key, V value) { jaroslav@597: synchronized (mutex) {return m.put(key, value);} jaroslav@597: } jaroslav@597: public V remove(Object key) { jaroslav@597: synchronized (mutex) {return m.remove(key);} jaroslav@597: } jaroslav@597: public void putAll(Map map) { jaroslav@597: synchronized (mutex) {m.putAll(map);} jaroslav@597: } jaroslav@597: public void clear() { jaroslav@597: synchronized (mutex) {m.clear();} jaroslav@597: } jaroslav@597: jaroslav@597: private transient Set keySet = null; jaroslav@597: private transient Set> entrySet = null; jaroslav@597: private transient Collection values = null; jaroslav@597: jaroslav@597: public Set keySet() { jaroslav@597: synchronized (mutex) { jaroslav@597: if (keySet==null) jaroslav@597: keySet = new SynchronizedSet<>(m.keySet(), mutex); jaroslav@597: return keySet; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: public Set> entrySet() { jaroslav@597: synchronized (mutex) { jaroslav@597: if (entrySet==null) jaroslav@597: entrySet = new SynchronizedSet<>(m.entrySet(), mutex); jaroslav@597: return entrySet; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: public Collection values() { jaroslav@597: synchronized (mutex) { jaroslav@597: if (values==null) jaroslav@597: values = new SynchronizedCollection<>(m.values(), mutex); jaroslav@597: return values; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: synchronized (mutex) {return m.equals(o);} jaroslav@597: } jaroslav@597: public int hashCode() { jaroslav@597: synchronized (mutex) {return m.hashCode();} jaroslav@597: } jaroslav@597: public String toString() { jaroslav@597: synchronized (mutex) {return m.toString();} jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a synchronized (thread-safe) sorted map backed by the specified jaroslav@597: * sorted map. In order to guarantee serial access, it is critical that jaroslav@597: * all access to the backing sorted map is accomplished jaroslav@597: * through the returned sorted map (or its views).

jaroslav@597: * jaroslav@597: * It is imperative that the user manually synchronize on the returned jaroslav@597: * sorted map when iterating over any of its collection views, or the jaroslav@597: * collections views of any of its subMap, headMap or jaroslav@597: * tailMap views. jaroslav@597: *

jaroslav@597:      *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
jaroslav@597:      *      ...
jaroslav@597:      *  Set s = m.keySet();  // Needn't be in synchronized block
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (m) {  // Synchronizing on m, not s!
jaroslav@597:      *      Iterator i = s.iterator(); // Must be in synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * or: jaroslav@597: *
jaroslav@597:      *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
jaroslav@597:      *  SortedMap m2 = m.subMap(foo, bar);
jaroslav@597:      *      ...
jaroslav@597:      *  Set s2 = m2.keySet();  // Needn't be in synchronized block
jaroslav@597:      *      ...
jaroslav@597:      *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
jaroslav@597:      *      Iterator i = s.iterator(); // Must be in synchronized block
jaroslav@597:      *      while (i.hasNext())
jaroslav@597:      *          foo(i.next());
jaroslav@597:      *  }
jaroslav@597:      * 
jaroslav@597: * Failure to follow this advice may result in non-deterministic behavior. jaroslav@597: * jaroslav@597: *

The returned sorted map will be serializable if the specified jaroslav@597: * sorted map is serializable. jaroslav@597: * jaroslav@597: * @param m the sorted map to be "wrapped" in a synchronized sorted map. jaroslav@597: * @return a synchronized view of the specified sorted map. jaroslav@597: */ jaroslav@597: public static SortedMap synchronizedSortedMap(SortedMap m) { jaroslav@597: return new SynchronizedSortedMap<>(m); jaroslav@597: } jaroslav@597: jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class SynchronizedSortedMap jaroslav@597: extends SynchronizedMap jaroslav@597: implements SortedMap jaroslav@597: { jaroslav@597: private static final long serialVersionUID = -8798146769416483793L; jaroslav@597: jaroslav@597: private final SortedMap sm; jaroslav@597: jaroslav@597: SynchronizedSortedMap(SortedMap m) { jaroslav@597: super(m); jaroslav@597: sm = m; jaroslav@597: } jaroslav@597: SynchronizedSortedMap(SortedMap m, Object mutex) { jaroslav@597: super(m, mutex); jaroslav@597: sm = m; jaroslav@597: } jaroslav@597: jaroslav@597: public Comparator comparator() { jaroslav@597: synchronized (mutex) {return sm.comparator();} jaroslav@597: } jaroslav@597: jaroslav@597: public SortedMap subMap(K fromKey, K toKey) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedSortedMap<>( jaroslav@597: sm.subMap(fromKey, toKey), mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: public SortedMap headMap(K toKey) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedSortedMap<>(sm.headMap(toKey), mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: public SortedMap tailMap(K fromKey) { jaroslav@597: synchronized (mutex) { jaroslav@597: return new SynchronizedSortedMap<>(sm.tailMap(fromKey),mutex); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: public K firstKey() { jaroslav@597: synchronized (mutex) {return sm.firstKey();} jaroslav@597: } jaroslav@597: public K lastKey() { jaroslav@597: synchronized (mutex) {return sm.lastKey();} jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: // Dynamically typesafe collection wrappers jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a dynamically typesafe view of the specified collection. jaroslav@597: * Any attempt to insert an element of the wrong type will result in an jaroslav@597: * immediate {@link ClassCastException}. Assuming a collection jaroslav@597: * contains no incorrectly typed elements prior to the time a jaroslav@597: * dynamically typesafe view is generated, and that all subsequent jaroslav@597: * access to the collection takes place through the view, it is jaroslav@597: * guaranteed that the collection cannot contain an incorrectly jaroslav@597: * typed element. jaroslav@597: * jaroslav@597: *

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

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

 {@code
jaroslav@597:      *     Collection c = new HashSet();
jaroslav@597:      * }
jaroslav@597: * may be replaced temporarily by this one: jaroslav@597: *
 {@code
jaroslav@597:      *     Collection c = Collections.checkedCollection(
jaroslav@597:      *         new HashSet(), String.class);
jaroslav@597:      * }
jaroslav@597: * Running the program again will cause it to fail at the point where jaroslav@597: * an incorrectly typed element is inserted into the collection, clearly jaroslav@597: * identifying the source of the problem. Once the problem is fixed, the jaroslav@597: * modified declaration may be reverted back to the original. jaroslav@597: * jaroslav@597: *

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

The returned collection will be serializable if the specified jaroslav@597: * collection is serializable. jaroslav@597: * jaroslav@597: *

Since {@code null} is considered to be a value of any reference jaroslav@597: * type, the returned collection permits insertion of null elements jaroslav@597: * whenever the backing collection does. jaroslav@597: * jaroslav@597: * @param c the collection for which a dynamically typesafe view is to be jaroslav@597: * returned jaroslav@597: * @param type the type of element that {@code c} is permitted to hold jaroslav@597: * @return a dynamically typesafe view of the specified collection jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static Collection checkedCollection(Collection c, jaroslav@597: Class type) { jaroslav@597: return new CheckedCollection<>(c, type); jaroslav@597: } jaroslav@597: jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: static T[] zeroLengthArray(Class type) { jaroslav@597: return (T[]) Array.newInstance(type, 0); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class CheckedCollection implements Collection, Serializable { jaroslav@597: private static final long serialVersionUID = 1578914078182001775L; jaroslav@597: jaroslav@597: final Collection c; jaroslav@597: final Class type; jaroslav@597: jaroslav@597: void typeCheck(Object o) { jaroslav@597: if (o != null && !type.isInstance(o)) jaroslav@597: throw new ClassCastException(badElementMsg(o)); jaroslav@597: } jaroslav@597: jaroslav@597: private String badElementMsg(Object o) { jaroslav@597: return "Attempt to insert " + o.getClass() + jaroslav@597: " element into collection with element type " + type; jaroslav@597: } jaroslav@597: jaroslav@597: CheckedCollection(Collection c, Class type) { jaroslav@597: if (c==null || type == null) jaroslav@597: throw new NullPointerException(); jaroslav@597: this.c = c; jaroslav@597: this.type = type; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() { return c.size(); } jaroslav@597: public boolean isEmpty() { return c.isEmpty(); } jaroslav@597: public boolean contains(Object o) { return c.contains(o); } jaroslav@597: public Object[] toArray() { return c.toArray(); } jaroslav@597: public T[] toArray(T[] a) { return c.toArray(a); } jaroslav@597: public String toString() { return c.toString(); } jaroslav@597: public boolean remove(Object o) { return c.remove(o); } jaroslav@597: public void clear() { c.clear(); } jaroslav@597: jaroslav@597: public boolean containsAll(Collection coll) { jaroslav@597: return c.containsAll(coll); jaroslav@597: } jaroslav@597: public boolean removeAll(Collection coll) { jaroslav@597: return c.removeAll(coll); jaroslav@597: } jaroslav@597: public boolean retainAll(Collection coll) { jaroslav@597: return c.retainAll(coll); jaroslav@597: } jaroslav@597: jaroslav@597: public Iterator iterator() { jaroslav@597: final Iterator it = c.iterator(); jaroslav@597: return new Iterator() { jaroslav@597: public boolean hasNext() { return it.hasNext(); } jaroslav@597: public E next() { return it.next(); } jaroslav@597: public void remove() { it.remove(); }}; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean add(E e) { jaroslav@597: typeCheck(e); jaroslav@597: return c.add(e); jaroslav@597: } jaroslav@597: jaroslav@597: private E[] zeroLengthElementArray = null; // Lazily initialized jaroslav@597: jaroslav@597: private E[] zeroLengthElementArray() { jaroslav@597: return zeroLengthElementArray != null ? zeroLengthElementArray : jaroslav@597: (zeroLengthElementArray = zeroLengthArray(type)); jaroslav@597: } jaroslav@597: jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: Collection checkedCopyOf(Collection coll) { jaroslav@597: Object[] a = null; jaroslav@597: try { jaroslav@597: E[] z = zeroLengthElementArray(); jaroslav@597: a = coll.toArray(z); jaroslav@597: // Defend against coll violating the toArray contract jaroslav@597: if (a.getClass() != z.getClass()) jaroslav@597: a = Arrays.copyOf(a, a.length, z.getClass()); jaroslav@597: } catch (ArrayStoreException ignore) { jaroslav@597: // To get better and consistent diagnostics, jaroslav@597: // we call typeCheck explicitly on each element. jaroslav@597: // We call clone() to defend against coll retaining a jaroslav@597: // reference to the returned array and storing a bad jaroslav@597: // element into it after it has been type checked. jaroslav@597: a = coll.toArray().clone(); jaroslav@597: for (Object o : a) jaroslav@597: typeCheck(o); jaroslav@597: } jaroslav@597: // A slight abuse of the type system, but safe here. jaroslav@597: return (Collection) Arrays.asList(a); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean addAll(Collection coll) { jaroslav@597: // Doing things this way insulates us from concurrent changes jaroslav@597: // in the contents of coll and provides all-or-nothing jaroslav@597: // semantics (which we wouldn't get if we type-checked each jaroslav@597: // element as we added it) jaroslav@597: return c.addAll(checkedCopyOf(coll)); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a dynamically typesafe view of the specified set. jaroslav@597: * Any attempt to insert an element of the wrong type will result in jaroslav@597: * an immediate {@link ClassCastException}. Assuming a set contains jaroslav@597: * no incorrectly typed elements prior to the time a dynamically typesafe jaroslav@597: * view is generated, and that all subsequent access to the set jaroslav@597: * takes place through the view, it is guaranteed that the jaroslav@597: * set cannot contain an incorrectly typed element. jaroslav@597: * jaroslav@597: *

A discussion of the use of dynamically typesafe views may be jaroslav@597: * found in the documentation for the {@link #checkedCollection jaroslav@597: * checkedCollection} method. jaroslav@597: * jaroslav@597: *

The returned set will be serializable if the specified set is jaroslav@597: * serializable. jaroslav@597: * jaroslav@597: *

Since {@code null} is considered to be a value of any reference jaroslav@597: * type, the returned set permits insertion of null elements whenever jaroslav@597: * the backing set does. jaroslav@597: * jaroslav@597: * @param s the set for which a dynamically typesafe view is to be jaroslav@597: * returned jaroslav@597: * @param type the type of element that {@code s} is permitted to hold jaroslav@597: * @return a dynamically typesafe view of the specified set jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static Set checkedSet(Set s, Class type) { jaroslav@597: return new CheckedSet<>(s, type); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class CheckedSet extends CheckedCollection jaroslav@597: implements Set, Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 4694047833775013803L; jaroslav@597: jaroslav@597: CheckedSet(Set s, Class elementType) { super(s, elementType); } jaroslav@597: jaroslav@597: public boolean equals(Object o) { return o == this || c.equals(o); } jaroslav@597: public int hashCode() { return c.hashCode(); } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a dynamically typesafe view of the specified sorted set. jaroslav@597: * Any attempt to insert an element of the wrong type will result in an jaroslav@597: * immediate {@link ClassCastException}. Assuming a sorted set jaroslav@597: * contains no incorrectly typed elements prior to the time a jaroslav@597: * dynamically typesafe view is generated, and that all subsequent jaroslav@597: * access to the sorted set takes place through the view, it is jaroslav@597: * guaranteed that the sorted set cannot contain an incorrectly jaroslav@597: * typed element. jaroslav@597: * jaroslav@597: *

A discussion of the use of dynamically typesafe views may be jaroslav@597: * found in the documentation for the {@link #checkedCollection jaroslav@597: * checkedCollection} method. jaroslav@597: * jaroslav@597: *

The returned sorted set will be serializable if the specified sorted jaroslav@597: * set is serializable. jaroslav@597: * jaroslav@597: *

Since {@code null} is considered to be a value of any reference jaroslav@597: * type, the returned sorted set permits insertion of null elements jaroslav@597: * whenever the backing sorted set does. jaroslav@597: * jaroslav@597: * @param s the sorted set for which a dynamically typesafe view is to be jaroslav@597: * returned jaroslav@597: * @param type the type of element that {@code s} is permitted to hold jaroslav@597: * @return a dynamically typesafe view of the specified sorted set jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static SortedSet checkedSortedSet(SortedSet s, jaroslav@597: Class type) { jaroslav@597: return new CheckedSortedSet<>(s, type); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class CheckedSortedSet extends CheckedSet jaroslav@597: implements SortedSet, Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 1599911165492914959L; jaroslav@597: private final SortedSet ss; jaroslav@597: jaroslav@597: CheckedSortedSet(SortedSet s, Class type) { jaroslav@597: super(s, type); jaroslav@597: ss = s; jaroslav@597: } jaroslav@597: jaroslav@597: public Comparator comparator() { return ss.comparator(); } jaroslav@597: public E first() { return ss.first(); } jaroslav@597: public E last() { return ss.last(); } jaroslav@597: jaroslav@597: public SortedSet subSet(E fromElement, E toElement) { jaroslav@597: return checkedSortedSet(ss.subSet(fromElement,toElement), type); jaroslav@597: } jaroslav@597: public SortedSet headSet(E toElement) { jaroslav@597: return checkedSortedSet(ss.headSet(toElement), type); jaroslav@597: } jaroslav@597: public SortedSet tailSet(E fromElement) { jaroslav@597: return checkedSortedSet(ss.tailSet(fromElement), type); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a dynamically typesafe view of the specified list. jaroslav@597: * Any attempt to insert an element of the wrong type will result in jaroslav@597: * an immediate {@link ClassCastException}. Assuming a list contains jaroslav@597: * no incorrectly typed elements prior to the time a dynamically typesafe jaroslav@597: * view is generated, and that all subsequent access to the list jaroslav@597: * takes place through the view, it is guaranteed that the jaroslav@597: * list cannot contain an incorrectly typed element. jaroslav@597: * jaroslav@597: *

A discussion of the use of dynamically typesafe views may be jaroslav@597: * found in the documentation for the {@link #checkedCollection jaroslav@597: * checkedCollection} method. jaroslav@597: * jaroslav@597: *

The returned list will be serializable if the specified list jaroslav@597: * is serializable. jaroslav@597: * jaroslav@597: *

Since {@code null} is considered to be a value of any reference jaroslav@597: * type, the returned list permits insertion of null elements whenever jaroslav@597: * the backing list does. jaroslav@597: * jaroslav@597: * @param list the list for which a dynamically typesafe view is to be jaroslav@597: * returned jaroslav@597: * @param type the type of element that {@code list} is permitted to hold jaroslav@597: * @return a dynamically typesafe view of the specified list jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static List checkedList(List list, Class type) { jaroslav@597: return (list instanceof RandomAccess ? jaroslav@597: new CheckedRandomAccessList<>(list, type) : jaroslav@597: new CheckedList<>(list, type)); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class CheckedList jaroslav@597: extends CheckedCollection jaroslav@597: implements List jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 65247728283967356L; jaroslav@597: final List list; jaroslav@597: jaroslav@597: CheckedList(List list, Class type) { jaroslav@597: super(list, type); jaroslav@597: this.list = list; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { return o == this || list.equals(o); } jaroslav@597: public int hashCode() { return list.hashCode(); } jaroslav@597: public E get(int index) { return list.get(index); } jaroslav@597: public E remove(int index) { return list.remove(index); } jaroslav@597: public int indexOf(Object o) { return list.indexOf(o); } jaroslav@597: public int lastIndexOf(Object o) { return list.lastIndexOf(o); } jaroslav@597: jaroslav@597: public E set(int index, E element) { jaroslav@597: typeCheck(element); jaroslav@597: return list.set(index, element); jaroslav@597: } jaroslav@597: jaroslav@597: public void add(int index, E element) { jaroslav@597: typeCheck(element); jaroslav@597: list.add(index, element); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean addAll(int index, Collection c) { jaroslav@597: return list.addAll(index, checkedCopyOf(c)); jaroslav@597: } jaroslav@597: public ListIterator listIterator() { return listIterator(0); } jaroslav@597: jaroslav@597: public ListIterator listIterator(final int index) { jaroslav@597: final ListIterator i = list.listIterator(index); jaroslav@597: jaroslav@597: return new ListIterator() { jaroslav@597: public boolean hasNext() { return i.hasNext(); } jaroslav@597: public E next() { return i.next(); } jaroslav@597: public boolean hasPrevious() { return i.hasPrevious(); } jaroslav@597: public E previous() { return i.previous(); } jaroslav@597: public int nextIndex() { return i.nextIndex(); } jaroslav@597: public int previousIndex() { return i.previousIndex(); } jaroslav@597: public void remove() { i.remove(); } jaroslav@597: jaroslav@597: public void set(E e) { jaroslav@597: typeCheck(e); jaroslav@597: i.set(e); jaroslav@597: } jaroslav@597: jaroslav@597: public void add(E e) { jaroslav@597: typeCheck(e); jaroslav@597: i.add(e); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: return new CheckedList<>(list.subList(fromIndex, toIndex), type); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class CheckedRandomAccessList extends CheckedList jaroslav@597: implements RandomAccess jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 1638200125423088369L; jaroslav@597: jaroslav@597: CheckedRandomAccessList(List list, Class type) { jaroslav@597: super(list, type); jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: return new CheckedRandomAccessList<>( jaroslav@597: list.subList(fromIndex, toIndex), type); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a dynamically typesafe view of the specified map. jaroslav@597: * Any attempt to insert a mapping whose key or value have the wrong jaroslav@597: * type will result in an immediate {@link ClassCastException}. jaroslav@597: * Similarly, any attempt to modify the value currently associated with jaroslav@597: * a key will result in an immediate {@link ClassCastException}, jaroslav@597: * whether the modification is attempted directly through the map jaroslav@597: * itself, or through a {@link Map.Entry} instance obtained from the jaroslav@597: * map's {@link Map#entrySet() entry set} view. jaroslav@597: * jaroslav@597: *

Assuming a map contains no incorrectly typed keys or values jaroslav@597: * prior to the time a dynamically typesafe view is generated, and jaroslav@597: * that all subsequent access to the map takes place through the view jaroslav@597: * (or one of its collection views), it is guaranteed that the jaroslav@597: * map cannot contain an incorrectly typed key or value. jaroslav@597: * jaroslav@597: *

A discussion of the use of dynamically typesafe views may be jaroslav@597: * found in the documentation for the {@link #checkedCollection jaroslav@597: * checkedCollection} method. jaroslav@597: * jaroslav@597: *

The returned map will be serializable if the specified map is jaroslav@597: * serializable. jaroslav@597: * jaroslav@597: *

Since {@code null} is considered to be a value of any reference jaroslav@597: * type, the returned map permits insertion of null keys or values jaroslav@597: * whenever the backing map does. jaroslav@597: * jaroslav@597: * @param m the map for which a dynamically typesafe view is to be jaroslav@597: * returned jaroslav@597: * @param keyType the type of key that {@code m} is permitted to hold jaroslav@597: * @param valueType the type of value that {@code m} is permitted to hold jaroslav@597: * @return a dynamically typesafe view of the specified map jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static Map checkedMap(Map m, jaroslav@597: Class keyType, jaroslav@597: Class valueType) { jaroslav@597: return new CheckedMap<>(m, keyType, valueType); jaroslav@597: } jaroslav@597: jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class CheckedMap jaroslav@597: implements Map, Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 5742860141034234728L; jaroslav@597: jaroslav@597: private final Map m; jaroslav@597: final Class keyType; jaroslav@597: final Class valueType; jaroslav@597: jaroslav@597: private void typeCheck(Object key, Object value) { jaroslav@597: if (key != null && !keyType.isInstance(key)) jaroslav@597: throw new ClassCastException(badKeyMsg(key)); jaroslav@597: jaroslav@597: if (value != null && !valueType.isInstance(value)) jaroslav@597: throw new ClassCastException(badValueMsg(value)); jaroslav@597: } jaroslav@597: jaroslav@597: private String badKeyMsg(Object key) { jaroslav@597: return "Attempt to insert " + key.getClass() + jaroslav@597: " key into map with key type " + keyType; jaroslav@597: } jaroslav@597: jaroslav@597: private String badValueMsg(Object value) { jaroslav@597: return "Attempt to insert " + value.getClass() + jaroslav@597: " value into map with value type " + valueType; jaroslav@597: } jaroslav@597: jaroslav@597: CheckedMap(Map m, Class keyType, Class valueType) { jaroslav@597: if (m == null || keyType == null || valueType == null) jaroslav@597: throw new NullPointerException(); jaroslav@597: this.m = m; jaroslav@597: this.keyType = keyType; jaroslav@597: this.valueType = valueType; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() { return m.size(); } jaroslav@597: public boolean isEmpty() { return m.isEmpty(); } jaroslav@597: public boolean containsKey(Object key) { return m.containsKey(key); } jaroslav@597: public boolean containsValue(Object v) { return m.containsValue(v); } jaroslav@597: public V get(Object key) { return m.get(key); } jaroslav@597: public V remove(Object key) { return m.remove(key); } jaroslav@597: public void clear() { m.clear(); } jaroslav@597: public Set keySet() { return m.keySet(); } jaroslav@597: public Collection values() { return m.values(); } jaroslav@597: public boolean equals(Object o) { return o == this || m.equals(o); } jaroslav@597: public int hashCode() { return m.hashCode(); } jaroslav@597: public String toString() { return m.toString(); } jaroslav@597: jaroslav@597: public V put(K key, V value) { jaroslav@597: typeCheck(key, value); jaroslav@597: return m.put(key, value); jaroslav@597: } jaroslav@597: jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public void putAll(Map t) { jaroslav@597: // Satisfy the following goals: jaroslav@597: // - good diagnostics in case of type mismatch jaroslav@597: // - all-or-nothing semantics jaroslav@597: // - protection from malicious t jaroslav@597: // - correct behavior if t is a concurrent map jaroslav@597: Object[] entries = t.entrySet().toArray(); jaroslav@597: List> checked = new ArrayList<>(entries.length); jaroslav@597: for (Object o : entries) { jaroslav@597: Map.Entry e = (Map.Entry) o; jaroslav@597: Object k = e.getKey(); jaroslav@597: Object v = e.getValue(); jaroslav@597: typeCheck(k, v); jaroslav@597: checked.add( jaroslav@597: new AbstractMap.SimpleImmutableEntry<>((K) k, (V) v)); jaroslav@597: } jaroslav@597: for (Map.Entry e : checked) jaroslav@597: m.put(e.getKey(), e.getValue()); jaroslav@597: } jaroslav@597: jaroslav@597: private transient Set> entrySet = null; jaroslav@597: jaroslav@597: public Set> entrySet() { jaroslav@597: if (entrySet==null) jaroslav@597: entrySet = new CheckedEntrySet<>(m.entrySet(), valueType); jaroslav@597: return entrySet; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * We need this class in addition to CheckedSet as Map.Entry permits jaroslav@597: * modification of the backing Map via the setValue operation. This jaroslav@597: * class is subtle: there are many possible attacks that must be jaroslav@597: * thwarted. jaroslav@597: * jaroslav@597: * @serial exclude jaroslav@597: */ jaroslav@597: static class CheckedEntrySet implements Set> { jaroslav@597: private final Set> s; jaroslav@597: private final Class valueType; jaroslav@597: jaroslav@597: CheckedEntrySet(Set> s, Class valueType) { jaroslav@597: this.s = s; jaroslav@597: this.valueType = valueType; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() { return s.size(); } jaroslav@597: public boolean isEmpty() { return s.isEmpty(); } jaroslav@597: public String toString() { return s.toString(); } jaroslav@597: public int hashCode() { return s.hashCode(); } jaroslav@597: public void clear() { s.clear(); } jaroslav@597: jaroslav@597: public boolean add(Map.Entry e) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: public boolean addAll(Collection> coll) { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: jaroslav@597: public Iterator> iterator() { jaroslav@597: final Iterator> i = s.iterator(); jaroslav@597: final Class valueType = this.valueType; jaroslav@597: jaroslav@597: return new Iterator>() { jaroslav@597: public boolean hasNext() { return i.hasNext(); } jaroslav@597: public void remove() { i.remove(); } jaroslav@597: jaroslav@597: public Map.Entry next() { jaroslav@597: return checkedEntry(i.next(), valueType); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public Object[] toArray() { jaroslav@597: Object[] source = s.toArray(); jaroslav@597: jaroslav@597: /* jaroslav@597: * Ensure that we don't get an ArrayStoreException even if jaroslav@597: * s.toArray returns an array of something other than Object jaroslav@597: */ jaroslav@597: Object[] dest = (CheckedEntry.class.isInstance( jaroslav@597: source.getClass().getComponentType()) ? source : jaroslav@597: new Object[source.length]); jaroslav@597: jaroslav@597: for (int i = 0; i < source.length; i++) jaroslav@597: dest[i] = checkedEntry((Map.Entry)source[i], jaroslav@597: valueType); jaroslav@597: return dest; jaroslav@597: } jaroslav@597: jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: // We don't pass a to s.toArray, to avoid window of jaroslav@597: // vulnerability wherein an unscrupulous multithreaded client jaroslav@597: // could get his hands on raw (unwrapped) Entries from s. jaroslav@597: T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0)); jaroslav@597: jaroslav@597: for (int i=0; i)arr[i], jaroslav@597: valueType); jaroslav@597: if (arr.length > a.length) jaroslav@597: return arr; jaroslav@597: jaroslav@597: System.arraycopy(arr, 0, a, 0, arr.length); jaroslav@597: if (a.length > arr.length) jaroslav@597: a[arr.length] = null; jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * This method is overridden to protect the backing set against jaroslav@597: * an object with a nefarious equals function that senses jaroslav@597: * that the equality-candidate is Map.Entry and calls its jaroslav@597: * setValue method. jaroslav@597: */ jaroslav@597: public boolean contains(Object o) { jaroslav@597: if (!(o instanceof Map.Entry)) jaroslav@597: return false; jaroslav@597: Map.Entry e = (Map.Entry) o; jaroslav@597: return s.contains( jaroslav@597: (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType)); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * The bulk collection methods are overridden to protect jaroslav@597: * against an unscrupulous collection whose contains(Object o) jaroslav@597: * method senses when o is a Map.Entry, and calls o.setValue. jaroslav@597: */ jaroslav@597: public boolean containsAll(Collection c) { jaroslav@597: for (Object o : c) jaroslav@597: if (!contains(o)) // Invokes safe contains() above jaroslav@597: return false; jaroslav@597: return true; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean remove(Object o) { jaroslav@597: if (!(o instanceof Map.Entry)) jaroslav@597: return false; jaroslav@597: return s.remove(new AbstractMap.SimpleImmutableEntry jaroslav@597: <>((Map.Entry)o)); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean removeAll(Collection c) { jaroslav@597: return batchRemove(c, false); jaroslav@597: } jaroslav@597: public boolean retainAll(Collection c) { jaroslav@597: return batchRemove(c, true); jaroslav@597: } jaroslav@597: private boolean batchRemove(Collection c, boolean complement) { jaroslav@597: boolean modified = false; jaroslav@597: Iterator> it = iterator(); jaroslav@597: while (it.hasNext()) { jaroslav@597: if (c.contains(it.next()) != complement) { jaroslav@597: it.remove(); jaroslav@597: modified = true; jaroslav@597: } jaroslav@597: } jaroslav@597: return modified; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: if (o == this) jaroslav@597: return true; jaroslav@597: if (!(o instanceof Set)) jaroslav@597: return false; jaroslav@597: Set that = (Set) o; jaroslav@597: return that.size() == s.size() jaroslav@597: && containsAll(that); // Invokes safe containsAll() above jaroslav@597: } jaroslav@597: jaroslav@597: static CheckedEntry checkedEntry(Map.Entry e, jaroslav@597: Class valueType) { jaroslav@597: return new CheckedEntry<>(e, valueType); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * This "wrapper class" serves two purposes: it prevents jaroslav@597: * the client from modifying the backing Map, by short-circuiting jaroslav@597: * the setValue method, and it protects the backing Map against jaroslav@597: * an ill-behaved Map.Entry that attempts to modify another jaroslav@597: * Map.Entry when asked to perform an equality check. jaroslav@597: */ jaroslav@597: private static class CheckedEntry implements Map.Entry { jaroslav@597: private final Map.Entry e; jaroslav@597: private final Class valueType; jaroslav@597: jaroslav@597: CheckedEntry(Map.Entry e, Class valueType) { jaroslav@597: this.e = e; jaroslav@597: this.valueType = valueType; jaroslav@597: } jaroslav@597: jaroslav@597: public K getKey() { return e.getKey(); } jaroslav@597: public V getValue() { return e.getValue(); } jaroslav@597: public int hashCode() { return e.hashCode(); } jaroslav@597: public String toString() { return e.toString(); } jaroslav@597: jaroslav@597: public V setValue(V value) { jaroslav@597: if (value != null && !valueType.isInstance(value)) jaroslav@597: throw new ClassCastException(badValueMsg(value)); jaroslav@597: return e.setValue(value); jaroslav@597: } jaroslav@597: jaroslav@597: private String badValueMsg(Object value) { jaroslav@597: return "Attempt to insert " + value.getClass() + jaroslav@597: " value into map with value type " + valueType; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: if (o == this) jaroslav@597: return true; jaroslav@597: if (!(o instanceof Map.Entry)) jaroslav@597: return false; jaroslav@597: return e.equals(new AbstractMap.SimpleImmutableEntry jaroslav@597: <>((Map.Entry)o)); jaroslav@597: } jaroslav@597: } jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a dynamically typesafe view of the specified sorted map. jaroslav@597: * Any attempt to insert a mapping whose key or value have the wrong jaroslav@597: * type will result in an immediate {@link ClassCastException}. jaroslav@597: * Similarly, any attempt to modify the value currently associated with jaroslav@597: * a key will result in an immediate {@link ClassCastException}, jaroslav@597: * whether the modification is attempted directly through the map jaroslav@597: * itself, or through a {@link Map.Entry} instance obtained from the jaroslav@597: * map's {@link Map#entrySet() entry set} view. jaroslav@597: * jaroslav@597: *

Assuming a map contains no incorrectly typed keys or values jaroslav@597: * prior to the time a dynamically typesafe view is generated, and jaroslav@597: * that all subsequent access to the map takes place through the view jaroslav@597: * (or one of its collection views), it is guaranteed that the jaroslav@597: * map cannot contain an incorrectly typed key or value. jaroslav@597: * jaroslav@597: *

A discussion of the use of dynamically typesafe views may be jaroslav@597: * found in the documentation for the {@link #checkedCollection jaroslav@597: * checkedCollection} method. jaroslav@597: * jaroslav@597: *

The returned map will be serializable if the specified map is jaroslav@597: * serializable. jaroslav@597: * jaroslav@597: *

Since {@code null} is considered to be a value of any reference jaroslav@597: * type, the returned map permits insertion of null keys or values jaroslav@597: * whenever the backing map does. jaroslav@597: * jaroslav@597: * @param m the map for which a dynamically typesafe view is to be jaroslav@597: * returned jaroslav@597: * @param keyType the type of key that {@code m} is permitted to hold jaroslav@597: * @param valueType the type of value that {@code m} is permitted to hold jaroslav@597: * @return a dynamically typesafe view of the specified map jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static SortedMap checkedSortedMap(SortedMap m, jaroslav@597: Class keyType, jaroslav@597: Class valueType) { jaroslav@597: return new CheckedSortedMap<>(m, keyType, valueType); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class CheckedSortedMap extends CheckedMap jaroslav@597: implements SortedMap, Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 1599671320688067438L; jaroslav@597: jaroslav@597: private final SortedMap sm; jaroslav@597: jaroslav@597: CheckedSortedMap(SortedMap m, jaroslav@597: Class keyType, Class valueType) { jaroslav@597: super(m, keyType, valueType); jaroslav@597: sm = m; jaroslav@597: } jaroslav@597: jaroslav@597: public Comparator comparator() { return sm.comparator(); } jaroslav@597: public K firstKey() { return sm.firstKey(); } jaroslav@597: public K lastKey() { return sm.lastKey(); } jaroslav@597: jaroslav@597: public SortedMap subMap(K fromKey, K toKey) { jaroslav@597: return checkedSortedMap(sm.subMap(fromKey, toKey), jaroslav@597: keyType, valueType); jaroslav@597: } jaroslav@597: public SortedMap headMap(K toKey) { jaroslav@597: return checkedSortedMap(sm.headMap(toKey), keyType, valueType); jaroslav@597: } jaroslav@597: public SortedMap tailMap(K fromKey) { jaroslav@597: return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: // Empty collections jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an iterator that has no elements. More precisely, jaroslav@597: * jaroslav@597: *

jaroslav@597: * jaroslav@597: *

Implementations of this method are permitted, but not jaroslav@597: * required, to return the same object from multiple invocations. jaroslav@597: * jaroslav@597: * @return an empty iterator jaroslav@597: * @since 1.7 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static Iterator emptyIterator() { jaroslav@597: return (Iterator) EmptyIterator.EMPTY_ITERATOR; jaroslav@597: } jaroslav@597: jaroslav@597: private static class EmptyIterator implements Iterator { jaroslav@597: static final EmptyIterator EMPTY_ITERATOR jaroslav@597: = new EmptyIterator<>(); jaroslav@597: jaroslav@597: public boolean hasNext() { return false; } jaroslav@597: public E next() { throw new NoSuchElementException(); } jaroslav@597: public void remove() { throw new IllegalStateException(); } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a list iterator that has no elements. More precisely, jaroslav@597: * jaroslav@597: *
    jaroslav@597: * jaroslav@597: *
  • {@link Iterator#hasNext hasNext} and {@link jaroslav@597: * ListIterator#hasPrevious hasPrevious} always return {@code jaroslav@597: * false}. jaroslav@597: * jaroslav@597: *
  • {@link Iterator#next next} and {@link ListIterator#previous jaroslav@597: * previous} always throw {@link NoSuchElementException}. jaroslav@597: * jaroslav@597: *
  • {@link Iterator#remove remove} and {@link ListIterator#set jaroslav@597: * set} always throw {@link IllegalStateException}. jaroslav@597: * jaroslav@597: *
  • {@link ListIterator#add add} always throws {@link jaroslav@597: * UnsupportedOperationException}. jaroslav@597: * jaroslav@597: *
  • {@link ListIterator#nextIndex nextIndex} always returns jaroslav@597: * {@code 0} . jaroslav@597: * jaroslav@597: *
  • {@link ListIterator#previousIndex previousIndex} always jaroslav@597: * returns {@code -1}. jaroslav@597: * jaroslav@597: *
jaroslav@597: * jaroslav@597: *

Implementations of this method are permitted, but not jaroslav@597: * required, to return the same object from multiple invocations. jaroslav@597: * jaroslav@597: * @return an empty list iterator jaroslav@597: * @since 1.7 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static ListIterator emptyListIterator() { jaroslav@597: return (ListIterator) EmptyListIterator.EMPTY_ITERATOR; jaroslav@597: } jaroslav@597: jaroslav@597: private static class EmptyListIterator jaroslav@597: extends EmptyIterator jaroslav@597: implements ListIterator jaroslav@597: { jaroslav@597: static final EmptyListIterator EMPTY_ITERATOR jaroslav@597: = new EmptyListIterator<>(); jaroslav@597: jaroslav@597: public boolean hasPrevious() { return false; } jaroslav@597: public E previous() { throw new NoSuchElementException(); } jaroslav@597: public int nextIndex() { return 0; } jaroslav@597: public int previousIndex() { return -1; } jaroslav@597: public void set(E e) { throw new IllegalStateException(); } jaroslav@597: public void add(E e) { throw new UnsupportedOperationException(); } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an enumeration that has no elements. More precisely, jaroslav@597: * jaroslav@597: *
    jaroslav@597: * jaroslav@597: *
  • {@link Enumeration#hasMoreElements hasMoreElements} always jaroslav@597: * returns {@code false}. jaroslav@597: * jaroslav@597: *
  • {@link Enumeration#nextElement nextElement} always throws jaroslav@597: * {@link NoSuchElementException}. jaroslav@597: * jaroslav@597: *
jaroslav@597: * jaroslav@597: *

Implementations of this method are permitted, but not jaroslav@597: * required, to return the same object from multiple invocations. jaroslav@597: * jaroslav@597: * @return an empty enumeration jaroslav@597: * @since 1.7 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static Enumeration emptyEnumeration() { jaroslav@597: return (Enumeration) EmptyEnumeration.EMPTY_ENUMERATION; jaroslav@597: } jaroslav@597: jaroslav@597: private static class EmptyEnumeration implements Enumeration { jaroslav@597: static final EmptyEnumeration EMPTY_ENUMERATION jaroslav@597: = new EmptyEnumeration<>(); jaroslav@597: jaroslav@597: public boolean hasMoreElements() { return false; } jaroslav@597: public E nextElement() { throw new NoSuchElementException(); } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * The empty set (immutable). This set is serializable. jaroslav@597: * jaroslav@597: * @see #emptySet() jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static final Set EMPTY_SET = new EmptySet<>(); jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the empty set (immutable). This set is serializable. jaroslav@597: * Unlike the like-named field, this method is parameterized. jaroslav@597: * jaroslav@597: *

This example illustrates the type-safe way to obtain an empty set: jaroslav@597: *

jaroslav@597:      *     Set<String> s = Collections.emptySet();
jaroslav@597:      * 
jaroslav@597: * Implementation note: Implementations of this method need not jaroslav@597: * create a separate Set object for each call. Using this jaroslav@597: * method is likely to have comparable cost to using the like-named jaroslav@597: * field. (Unlike this method, the field does not provide type safety.) jaroslav@597: * jaroslav@597: * @see #EMPTY_SET jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static final Set emptySet() { jaroslav@597: return (Set) EMPTY_SET; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class EmptySet jaroslav@597: extends AbstractSet jaroslav@597: implements Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 1582296315990362920L; jaroslav@597: jaroslav@597: public Iterator iterator() { return emptyIterator(); } jaroslav@597: jaroslav@597: public int size() {return 0;} jaroslav@597: public boolean isEmpty() {return true;} jaroslav@597: jaroslav@597: public boolean contains(Object obj) {return false;} jaroslav@597: public boolean containsAll(Collection c) { return c.isEmpty(); } jaroslav@597: jaroslav@597: public Object[] toArray() { return new Object[0]; } jaroslav@597: jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: if (a.length > 0) jaroslav@597: a[0] = null; jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: // Preserves singleton property jaroslav@597: private Object readResolve() { jaroslav@597: return EMPTY_SET; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * The empty list (immutable). This list is serializable. jaroslav@597: * jaroslav@597: * @see #emptyList() jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static final List EMPTY_LIST = new EmptyList<>(); jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the empty list (immutable). This list is serializable. jaroslav@597: * jaroslav@597: *

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

jaroslav@597:      *     List<String> s = Collections.emptyList();
jaroslav@597:      * 
jaroslav@597: * Implementation note: Implementations of this method need not jaroslav@597: * create a separate List object for each call. Using this jaroslav@597: * method is likely to have comparable cost to using the like-named jaroslav@597: * field. (Unlike this method, the field does not provide type safety.) jaroslav@597: * jaroslav@597: * @see #EMPTY_LIST jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static final List emptyList() { jaroslav@597: return (List) EMPTY_LIST; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class EmptyList jaroslav@597: extends AbstractList jaroslav@597: implements RandomAccess, Serializable { jaroslav@597: private static final long serialVersionUID = 8842843931221139166L; jaroslav@597: jaroslav@597: public Iterator iterator() { jaroslav@597: return emptyIterator(); jaroslav@597: } jaroslav@597: public ListIterator listIterator() { jaroslav@597: return emptyListIterator(); jaroslav@597: } jaroslav@597: jaroslav@597: public int size() {return 0;} jaroslav@597: public boolean isEmpty() {return true;} jaroslav@597: jaroslav@597: public boolean contains(Object obj) {return false;} jaroslav@597: public boolean containsAll(Collection c) { return c.isEmpty(); } jaroslav@597: jaroslav@597: public Object[] toArray() { return new Object[0]; } jaroslav@597: jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: if (a.length > 0) jaroslav@597: a[0] = null; jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: public E get(int index) { jaroslav@597: throw new IndexOutOfBoundsException("Index: "+index); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: return (o instanceof List) && ((List)o).isEmpty(); jaroslav@597: } jaroslav@597: jaroslav@597: public int hashCode() { return 1; } jaroslav@597: jaroslav@597: // Preserves singleton property jaroslav@597: private Object readResolve() { jaroslav@597: return EMPTY_LIST; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * The empty map (immutable). This map is serializable. jaroslav@597: * jaroslav@597: * @see #emptyMap() jaroslav@597: * @since 1.3 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static final Map EMPTY_MAP = new EmptyMap<>(); jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the empty map (immutable). This map is serializable. jaroslav@597: * jaroslav@597: *

This example illustrates the type-safe way to obtain an empty set: jaroslav@597: *

jaroslav@597:      *     Map<String, Date> s = Collections.emptyMap();
jaroslav@597:      * 
jaroslav@597: * Implementation note: Implementations of this method need not jaroslav@597: * create a separate Map object for each call. Using this jaroslav@597: * method is likely to have comparable cost to using the like-named jaroslav@597: * field. (Unlike this method, the field does not provide type safety.) jaroslav@597: * jaroslav@597: * @see #EMPTY_MAP jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: @SuppressWarnings("unchecked") jaroslav@597: public static final Map emptyMap() { jaroslav@597: return (Map) EMPTY_MAP; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class EmptyMap jaroslav@597: extends AbstractMap jaroslav@597: implements Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 6428348081105594320L; jaroslav@597: jaroslav@597: public int size() {return 0;} jaroslav@597: public boolean isEmpty() {return true;} jaroslav@597: public boolean containsKey(Object key) {return false;} jaroslav@597: public boolean containsValue(Object value) {return false;} jaroslav@597: public V get(Object key) {return null;} jaroslav@597: public Set keySet() {return emptySet();} jaroslav@597: public Collection values() {return emptySet();} jaroslav@597: public Set> entrySet() {return emptySet();} jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: return (o instanceof Map) && ((Map)o).isEmpty(); jaroslav@597: } jaroslav@597: jaroslav@597: public int hashCode() {return 0;} jaroslav@597: jaroslav@597: // Preserves singleton property jaroslav@597: private Object readResolve() { jaroslav@597: return EMPTY_MAP; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: // Singleton collections jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an immutable set containing only the specified object. jaroslav@597: * The returned set is serializable. jaroslav@597: * jaroslav@597: * @param o the sole object to be stored in the returned set. jaroslav@597: * @return an immutable set containing only the specified object. jaroslav@597: */ jaroslav@597: public static Set singleton(T o) { jaroslav@597: return new SingletonSet<>(o); jaroslav@597: } jaroslav@597: jaroslav@597: static Iterator singletonIterator(final E e) { jaroslav@597: return new Iterator() { jaroslav@597: private boolean hasNext = true; jaroslav@597: public boolean hasNext() { jaroslav@597: return hasNext; jaroslav@597: } jaroslav@597: public E next() { jaroslav@597: if (hasNext) { jaroslav@597: hasNext = false; jaroslav@597: return e; jaroslav@597: } jaroslav@597: throw new NoSuchElementException(); jaroslav@597: } jaroslav@597: public void remove() { jaroslav@597: throw new UnsupportedOperationException(); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class SingletonSet jaroslav@597: extends AbstractSet jaroslav@597: implements Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 3193687207550431679L; jaroslav@597: jaroslav@597: private final E element; jaroslav@597: jaroslav@597: SingletonSet(E e) {element = e;} jaroslav@597: jaroslav@597: public Iterator iterator() { jaroslav@597: return singletonIterator(element); jaroslav@597: } jaroslav@597: jaroslav@597: public int size() {return 1;} jaroslav@597: jaroslav@597: public boolean contains(Object o) {return eq(o, element);} jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an immutable list containing only the specified object. jaroslav@597: * The returned list is serializable. jaroslav@597: * jaroslav@597: * @param o the sole object to be stored in the returned list. jaroslav@597: * @return an immutable list containing only the specified object. jaroslav@597: * @since 1.3 jaroslav@597: */ jaroslav@597: public static List singletonList(T o) { jaroslav@597: return new SingletonList<>(o); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class SingletonList jaroslav@597: extends AbstractList jaroslav@597: implements RandomAccess, Serializable { jaroslav@597: jaroslav@597: private static final long serialVersionUID = 3093736618740652951L; jaroslav@597: jaroslav@597: private final E element; jaroslav@597: jaroslav@597: SingletonList(E obj) {element = obj;} jaroslav@597: jaroslav@597: public Iterator iterator() { jaroslav@597: return singletonIterator(element); jaroslav@597: } jaroslav@597: jaroslav@597: public int size() {return 1;} jaroslav@597: jaroslav@597: public boolean contains(Object obj) {return eq(obj, element);} jaroslav@597: jaroslav@597: public E get(int index) { jaroslav@597: if (index != 0) jaroslav@597: throw new IndexOutOfBoundsException("Index: "+index+", Size: 1"); jaroslav@597: return element; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an immutable map, mapping only the specified key to the jaroslav@597: * specified value. The returned map is serializable. jaroslav@597: * jaroslav@597: * @param key the sole key to be stored in the returned map. jaroslav@597: * @param value the value to which the returned map maps key. jaroslav@597: * @return an immutable map containing only the specified key-value jaroslav@597: * mapping. jaroslav@597: * @since 1.3 jaroslav@597: */ jaroslav@597: public static Map singletonMap(K key, V value) { jaroslav@597: return new SingletonMap<>(key, value); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class SingletonMap jaroslav@597: extends AbstractMap jaroslav@597: implements Serializable { jaroslav@597: private static final long serialVersionUID = -6979724477215052911L; jaroslav@597: jaroslav@597: private final K k; jaroslav@597: private final V v; jaroslav@597: jaroslav@597: SingletonMap(K key, V value) { jaroslav@597: k = key; jaroslav@597: v = value; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() {return 1;} jaroslav@597: jaroslav@597: public boolean isEmpty() {return false;} jaroslav@597: jaroslav@597: public boolean containsKey(Object key) {return eq(key, k);} jaroslav@597: jaroslav@597: public boolean containsValue(Object value) {return eq(value, v);} jaroslav@597: jaroslav@597: public V get(Object key) {return (eq(key, k) ? v : null);} jaroslav@597: jaroslav@597: private transient Set keySet = null; jaroslav@597: private transient Set> entrySet = null; jaroslav@597: private transient Collection values = null; jaroslav@597: jaroslav@597: public Set keySet() { jaroslav@597: if (keySet==null) jaroslav@597: keySet = singleton(k); jaroslav@597: return keySet; jaroslav@597: } jaroslav@597: jaroslav@597: public Set> entrySet() { jaroslav@597: if (entrySet==null) jaroslav@597: entrySet = Collections.>singleton( jaroslav@597: new SimpleImmutableEntry<>(k, v)); jaroslav@597: return entrySet; jaroslav@597: } jaroslav@597: jaroslav@597: public Collection values() { jaroslav@597: if (values==null) jaroslav@597: values = singleton(v); jaroslav@597: return values; jaroslav@597: } jaroslav@597: jaroslav@597: } jaroslav@597: jaroslav@597: // Miscellaneous jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an immutable list consisting of n copies of the jaroslav@597: * specified object. The newly allocated data object is tiny (it contains jaroslav@597: * a single reference to the data object). This method is useful in jaroslav@597: * combination with the List.addAll method to grow lists. jaroslav@597: * The returned list is serializable. jaroslav@597: * jaroslav@597: * @param n the number of elements in the returned list. jaroslav@597: * @param o the element to appear repeatedly in the returned list. jaroslav@597: * @return an immutable list consisting of n copies of the jaroslav@597: * specified object. jaroslav@597: * @throws IllegalArgumentException if {@code n < 0} jaroslav@597: * @see List#addAll(Collection) jaroslav@597: * @see List#addAll(int, Collection) jaroslav@597: */ jaroslav@597: public static List nCopies(int n, T o) { jaroslav@597: if (n < 0) jaroslav@597: throw new IllegalArgumentException("List length = " + n); jaroslav@597: return new CopiesList<>(n, o); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class CopiesList jaroslav@597: extends AbstractList jaroslav@597: implements RandomAccess, Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 2739099268398711800L; jaroslav@597: jaroslav@597: final int n; jaroslav@597: final E element; jaroslav@597: jaroslav@597: CopiesList(int n, E e) { jaroslav@597: assert n >= 0; jaroslav@597: this.n = n; jaroslav@597: element = e; jaroslav@597: } jaroslav@597: jaroslav@597: public int size() { jaroslav@597: return n; jaroslav@597: } jaroslav@597: jaroslav@597: public boolean contains(Object obj) { jaroslav@597: return n != 0 && eq(obj, element); jaroslav@597: } jaroslav@597: jaroslav@597: public int indexOf(Object o) { jaroslav@597: return contains(o) ? 0 : -1; jaroslav@597: } jaroslav@597: jaroslav@597: public int lastIndexOf(Object o) { jaroslav@597: return contains(o) ? n - 1 : -1; jaroslav@597: } jaroslav@597: jaroslav@597: public E get(int index) { jaroslav@597: if (index < 0 || index >= n) jaroslav@597: throw new IndexOutOfBoundsException("Index: "+index+ jaroslav@597: ", Size: "+n); jaroslav@597: return element; jaroslav@597: } jaroslav@597: jaroslav@597: public Object[] toArray() { jaroslav@597: final Object[] a = new Object[n]; jaroslav@597: if (element != null) jaroslav@597: Arrays.fill(a, 0, n, element); jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: final int n = this.n; jaroslav@597: if (a.length < n) { jaroslav@597: a = (T[])java.lang.reflect.Array jaroslav@597: .newInstance(a.getClass().getComponentType(), n); jaroslav@597: if (element != null) jaroslav@597: Arrays.fill(a, 0, n, element); jaroslav@597: } else { jaroslav@597: Arrays.fill(a, 0, n, element); jaroslav@597: if (a.length > n) jaroslav@597: a[n] = null; jaroslav@597: } jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: public List subList(int fromIndex, int toIndex) { jaroslav@597: if (fromIndex < 0) jaroslav@597: throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); jaroslav@597: if (toIndex > n) jaroslav@597: throw new IndexOutOfBoundsException("toIndex = " + toIndex); jaroslav@597: if (fromIndex > toIndex) jaroslav@597: throw new IllegalArgumentException("fromIndex(" + fromIndex + jaroslav@597: ") > toIndex(" + toIndex + ")"); jaroslav@597: return new CopiesList<>(toIndex - fromIndex, element); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a comparator that imposes the reverse of the natural jaroslav@597: * ordering on a collection of objects that implement the jaroslav@597: * {@code Comparable} interface. (The natural ordering is the ordering jaroslav@597: * imposed by the objects' own {@code compareTo} method.) This enables a jaroslav@597: * simple idiom for sorting (or maintaining) collections (or arrays) of jaroslav@597: * objects that implement the {@code Comparable} interface in jaroslav@597: * reverse-natural-order. For example, suppose {@code a} is an array of jaroslav@597: * strings. Then:
jaroslav@597:      *          Arrays.sort(a, Collections.reverseOrder());
jaroslav@597:      * 
sorts the array in reverse-lexicographic (alphabetical) order.

jaroslav@597: * jaroslav@597: * The returned comparator is serializable. jaroslav@597: * jaroslav@597: * @return A comparator that imposes the reverse of the natural jaroslav@597: * ordering on a collection of objects that implement jaroslav@597: * the Comparable interface. jaroslav@597: * @see Comparable jaroslav@597: */ jaroslav@597: public static Comparator reverseOrder() { jaroslav@597: return (Comparator) ReverseComparator.REVERSE_ORDER; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class ReverseComparator jaroslav@597: implements Comparator>, Serializable { jaroslav@597: jaroslav@597: private static final long serialVersionUID = 7207038068494060240L; jaroslav@597: jaroslav@597: static final ReverseComparator REVERSE_ORDER jaroslav@597: = new ReverseComparator(); jaroslav@597: jaroslav@597: public int compare(Comparable c1, Comparable c2) { jaroslav@597: return c2.compareTo(c1); jaroslav@597: } jaroslav@597: jaroslav@597: private Object readResolve() { return reverseOrder(); } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a comparator that imposes the reverse ordering of the specified jaroslav@597: * comparator. If the specified comparator is {@code null}, this method is jaroslav@597: * equivalent to {@link #reverseOrder()} (in other words, it returns a jaroslav@597: * comparator that imposes the reverse of the natural ordering on jaroslav@597: * a collection of objects that implement the Comparable interface). jaroslav@597: * jaroslav@597: *

The returned comparator is serializable (assuming the specified jaroslav@597: * comparator is also serializable or {@code null}). jaroslav@597: * jaroslav@597: * @param cmp a comparator who's ordering is to be reversed by the returned jaroslav@597: * comparator or {@code null} jaroslav@597: * @return A comparator that imposes the reverse ordering of the jaroslav@597: * specified comparator. jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static Comparator reverseOrder(Comparator cmp) { jaroslav@597: if (cmp == null) jaroslav@597: return reverseOrder(); jaroslav@597: jaroslav@597: if (cmp instanceof ReverseComparator2) jaroslav@597: return ((ReverseComparator2)cmp).cmp; jaroslav@597: jaroslav@597: return new ReverseComparator2<>(cmp); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class ReverseComparator2 implements Comparator, jaroslav@597: Serializable jaroslav@597: { jaroslav@597: private static final long serialVersionUID = 4374092139857L; jaroslav@597: jaroslav@597: /** jaroslav@597: * The comparator specified in the static factory. This will never jaroslav@597: * be null, as the static factory returns a ReverseComparator jaroslav@597: * instance if its argument is null. jaroslav@597: * jaroslav@597: * @serial jaroslav@597: */ jaroslav@597: final Comparator cmp; jaroslav@597: jaroslav@597: ReverseComparator2(Comparator cmp) { jaroslav@597: assert cmp != null; jaroslav@597: this.cmp = cmp; jaroslav@597: } jaroslav@597: jaroslav@597: public int compare(T t1, T t2) { jaroslav@597: return cmp.compare(t2, t1); jaroslav@597: } jaroslav@597: jaroslav@597: public boolean equals(Object o) { jaroslav@597: return (o == this) || jaroslav@597: (o instanceof ReverseComparator2 && jaroslav@597: cmp.equals(((ReverseComparator2)o).cmp)); jaroslav@597: } jaroslav@597: jaroslav@597: public int hashCode() { jaroslav@597: return cmp.hashCode() ^ Integer.MIN_VALUE; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an enumeration over the specified collection. This provides jaroslav@597: * interoperability with legacy APIs that require an enumeration jaroslav@597: * as input. jaroslav@597: * jaroslav@597: * @param c the collection for which an enumeration is to be returned. jaroslav@597: * @return an enumeration over the specified collection. jaroslav@597: * @see Enumeration jaroslav@597: */ jaroslav@597: public static Enumeration enumeration(final Collection c) { jaroslav@597: return new Enumeration() { jaroslav@597: private final Iterator i = c.iterator(); jaroslav@597: jaroslav@597: public boolean hasMoreElements() { jaroslav@597: return i.hasNext(); jaroslav@597: } jaroslav@597: jaroslav@597: public T nextElement() { jaroslav@597: return i.next(); jaroslav@597: } jaroslav@597: }; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an array list containing the elements returned by the jaroslav@597: * specified enumeration in the order they are returned by the jaroslav@597: * enumeration. This method provides interoperability between jaroslav@597: * legacy APIs that return enumerations and new APIs that require jaroslav@597: * collections. jaroslav@597: * jaroslav@597: * @param e enumeration providing elements for the returned jaroslav@597: * array list jaroslav@597: * @return an array list containing the elements returned jaroslav@597: * by the specified enumeration. jaroslav@597: * @since 1.4 jaroslav@597: * @see Enumeration jaroslav@597: * @see ArrayList jaroslav@597: */ jaroslav@597: public static ArrayList list(Enumeration e) { jaroslav@597: ArrayList l = new ArrayList<>(); jaroslav@597: while (e.hasMoreElements()) jaroslav@597: l.add(e.nextElement()); jaroslav@597: return l; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns true if the specified arguments are equal, or both null. jaroslav@597: */ jaroslav@597: static boolean eq(Object o1, Object o2) { jaroslav@597: return o1==null ? o2==null : o1.equals(o2); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the number of elements in the specified collection equal to the jaroslav@597: * specified object. More formally, returns the number of elements jaroslav@597: * e in the collection such that jaroslav@597: * (o == null ? e == null : o.equals(e)). jaroslav@597: * jaroslav@597: * @param c the collection in which to determine the frequency jaroslav@597: * of o jaroslav@597: * @param o the object whose frequency is to be determined jaroslav@597: * @throws NullPointerException if c is null jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static int frequency(Collection c, Object o) { jaroslav@597: int result = 0; jaroslav@597: if (o == null) { jaroslav@597: for (Object e : c) jaroslav@597: if (e == null) jaroslav@597: result++; jaroslav@597: } else { jaroslav@597: for (Object e : c) jaroslav@597: if (o.equals(e)) jaroslav@597: result++; jaroslav@597: } jaroslav@597: return result; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns {@code true} if the two specified collections have no jaroslav@597: * elements in common. jaroslav@597: * jaroslav@597: *

Care must be exercised if this method is used on collections that jaroslav@597: * do not comply with the general contract for {@code Collection}. jaroslav@597: * Implementations may elect to iterate over either collection and test jaroslav@597: * for containment in the other collection (or to perform any equivalent jaroslav@597: * computation). If either collection uses a nonstandard equality test jaroslav@597: * (as does a {@link SortedSet} whose ordering is not compatible with jaroslav@597: * equals, or the key set of an {@link IdentityHashMap}), both jaroslav@597: * collections must use the same nonstandard equality test, or the jaroslav@597: * result of this method is undefined. jaroslav@597: * jaroslav@597: *

Care must also be exercised when using collections that have jaroslav@597: * restrictions on the elements that they may contain. Collection jaroslav@597: * implementations are allowed to throw exceptions for any operation jaroslav@597: * involving elements they deem ineligible. For absolute safety the jaroslav@597: * specified collections should contain only elements which are jaroslav@597: * eligible elements for both collections. jaroslav@597: * jaroslav@597: *

Note that it is permissible to pass the same collection in both jaroslav@597: * parameters, in which case the method will return {@code true} if and jaroslav@597: * only if the collection is empty. jaroslav@597: * jaroslav@597: * @param c1 a collection jaroslav@597: * @param c2 a collection jaroslav@597: * @return {@code true} if the two specified collections have no jaroslav@597: * elements in common. jaroslav@597: * @throws NullPointerException if either collection is {@code null}. jaroslav@597: * @throws NullPointerException if one collection contains a {@code null} jaroslav@597: * element and {@code null} is not an eligible element for the other collection. jaroslav@597: * (optional) jaroslav@597: * @throws ClassCastException if one collection contains an element that is jaroslav@597: * of a type which is ineligible for the other collection. jaroslav@597: * (optional) jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: public static boolean disjoint(Collection c1, Collection c2) { jaroslav@597: // The collection to be used for contains(). Preference is given to jaroslav@597: // the collection who's contains() has lower O() complexity. jaroslav@597: Collection contains = c2; jaroslav@597: // The collection to be iterated. If the collections' contains() impl jaroslav@597: // are of different O() complexity, the collection with slower jaroslav@597: // contains() will be used for iteration. For collections who's jaroslav@597: // contains() are of the same complexity then best performance is jaroslav@597: // achieved by iterating the smaller collection. jaroslav@597: Collection iterate = c1; jaroslav@597: jaroslav@597: // Performance optimization cases. The heuristics: jaroslav@597: // 1. Generally iterate over c1. jaroslav@597: // 2. If c1 is a Set then iterate over c2. jaroslav@597: // 3. If either collection is empty then result is always true. jaroslav@597: // 4. Iterate over the smaller Collection. jaroslav@597: if (c1 instanceof Set) { jaroslav@597: // Use c1 for contains as a Set's contains() is expected to perform jaroslav@597: // better than O(N/2) jaroslav@597: iterate = c2; jaroslav@597: contains = c1; jaroslav@597: } else if (!(c2 instanceof Set)) { jaroslav@597: // Both are mere Collections. Iterate over smaller collection. jaroslav@597: // Example: If c1 contains 3 elements and c2 contains 50 elements and jaroslav@597: // assuming contains() requires ceiling(N/2) comparisons then jaroslav@597: // checking for all c1 elements in c2 would require 75 comparisons jaroslav@597: // (3 * ceiling(50/2)) vs. checking all c2 elements in c1 requiring jaroslav@597: // 100 comparisons (50 * ceiling(3/2)). jaroslav@597: int c1size = c1.size(); jaroslav@597: int c2size = c2.size(); jaroslav@597: if (c1size == 0 || c2size == 0) { jaroslav@597: // At least one collection is empty. Nothing will match. jaroslav@597: return true; jaroslav@597: } jaroslav@597: jaroslav@597: if (c1size > c2size) { jaroslav@597: iterate = c2; jaroslav@597: contains = c1; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: for (Object e : iterate) { jaroslav@597: if (contains.contains(e)) { jaroslav@597: // Found a common element. Collections are not disjoint. jaroslav@597: return false; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: // No common elements were found. jaroslav@597: return true; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Adds all of the specified elements to the specified collection. jaroslav@597: * Elements to be added may be specified individually or as an array. jaroslav@597: * The behavior of this convenience method is identical to that of jaroslav@597: * c.addAll(Arrays.asList(elements)), but this method is likely jaroslav@597: * to run significantly faster under most implementations. jaroslav@597: * jaroslav@597: *

When elements are specified individually, this method provides a jaroslav@597: * convenient way to add a few elements to an existing collection: jaroslav@597: *

jaroslav@597:      *     Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
jaroslav@597:      * 
jaroslav@597: * jaroslav@597: * @param c the collection into which elements are to be inserted jaroslav@597: * @param elements the elements to insert into c jaroslav@597: * @return true if the collection changed as a result of the call jaroslav@597: * @throws UnsupportedOperationException if c does not support jaroslav@597: * the add operation jaroslav@597: * @throws NullPointerException if elements contains one or more jaroslav@597: * null values and c does not permit null elements, or jaroslav@597: * if c or elements are null jaroslav@597: * @throws IllegalArgumentException if some property of a value in jaroslav@597: * elements prevents it from being added to c jaroslav@597: * @see Collection#addAll(Collection) jaroslav@597: * @since 1.5 jaroslav@597: */ jaroslav@597: @SafeVarargs jaroslav@597: public static boolean addAll(Collection c, T... elements) { jaroslav@597: boolean result = false; jaroslav@597: for (T element : elements) jaroslav@597: result |= c.add(element); jaroslav@597: return result; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a set backed by the specified map. The resulting set displays jaroslav@597: * the same ordering, concurrency, and performance characteristics as the jaroslav@597: * backing map. In essence, this factory method provides a {@link Set} jaroslav@597: * implementation corresponding to any {@link Map} implementation. There jaroslav@597: * is no need to use this method on a {@link Map} implementation that jaroslav@597: * already has a corresponding {@link Set} implementation (such as {@link jaroslav@597: * HashMap} or {@link TreeMap}). jaroslav@597: * jaroslav@597: *

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

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

jaroslav@597:      *    Set<Object> weakHashSet = Collections.newSetFromMap(
jaroslav@597:      *        new WeakHashMap<Object, Boolean>());
jaroslav@597:      * 
jaroslav@597: * jaroslav@597: * @param map the backing map jaroslav@597: * @return the set backed by the map jaroslav@597: * @throws IllegalArgumentException if map is not empty jaroslav@597: * @since 1.6 jaroslav@597: */ jaroslav@597: public static Set newSetFromMap(Map map) { jaroslav@597: return new SetFromMap<>(map); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: private static class SetFromMap extends AbstractSet jaroslav@597: implements Set, Serializable jaroslav@597: { jaroslav@597: private final Map m; // The backing map jaroslav@597: private transient Set s; // Its keySet jaroslav@597: jaroslav@597: SetFromMap(Map map) { jaroslav@597: if (!map.isEmpty()) jaroslav@597: throw new IllegalArgumentException("Map is non-empty"); jaroslav@597: m = map; jaroslav@597: s = map.keySet(); jaroslav@597: } jaroslav@597: jaroslav@597: public void clear() { m.clear(); } jaroslav@597: public int size() { return m.size(); } jaroslav@597: public boolean isEmpty() { return m.isEmpty(); } jaroslav@597: public boolean contains(Object o) { return m.containsKey(o); } jaroslav@597: public boolean remove(Object o) { return m.remove(o) != null; } jaroslav@597: public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; } jaroslav@597: public Iterator iterator() { return s.iterator(); } jaroslav@597: public Object[] toArray() { return s.toArray(); } jaroslav@597: public T[] toArray(T[] a) { return s.toArray(a); } jaroslav@597: public String toString() { return s.toString(); } jaroslav@597: public int hashCode() { return s.hashCode(); } jaroslav@597: public boolean equals(Object o) { return o == this || s.equals(o); } jaroslav@597: public boolean containsAll(Collection c) {return s.containsAll(c);} jaroslav@597: public boolean removeAll(Collection c) {return s.removeAll(c);} jaroslav@597: public boolean retainAll(Collection c) {return s.retainAll(c);} jaroslav@597: // addAll is the only inherited implementation jaroslav@597: jaroslav@597: private static final long serialVersionUID = 2454657854757543876L; jaroslav@597: jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo) jaroslav@597: * {@link Queue}. Method add is mapped to push, jaroslav@597: * remove is mapped to pop and so on. This jaroslav@597: * view can be useful when you would like to use a method jaroslav@597: * requiring a Queue but you need Lifo ordering. jaroslav@597: * jaroslav@597: *

Each method invocation on the queue returned by this method jaroslav@597: * results in exactly one method invocation on the backing deque, with jaroslav@597: * one exception. The {@link Queue#addAll addAll} method is jaroslav@597: * implemented as a sequence of {@link Deque#addFirst addFirst} jaroslav@597: * invocations on the backing deque. jaroslav@597: * jaroslav@597: * @param deque the deque jaroslav@597: * @return the queue jaroslav@597: * @since 1.6 jaroslav@597: */ jaroslav@597: public static Queue asLifoQueue(Deque deque) { jaroslav@597: return new AsLIFOQueue<>(deque); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @serial include jaroslav@597: */ jaroslav@597: static class AsLIFOQueue extends AbstractQueue jaroslav@597: implements Queue, Serializable { jaroslav@597: private static final long serialVersionUID = 1802017725587941708L; jaroslav@597: private final Deque q; jaroslav@597: AsLIFOQueue(Deque q) { this.q = q; } jaroslav@597: public boolean add(E e) { q.addFirst(e); return true; } jaroslav@597: public boolean offer(E e) { return q.offerFirst(e); } jaroslav@597: public E poll() { return q.pollFirst(); } jaroslav@597: public E remove() { return q.removeFirst(); } jaroslav@597: public E peek() { return q.peekFirst(); } jaroslav@597: public E element() { return q.getFirst(); } jaroslav@597: public void clear() { q.clear(); } jaroslav@597: public int size() { return q.size(); } jaroslav@597: public boolean isEmpty() { return q.isEmpty(); } jaroslav@597: public boolean contains(Object o) { return q.contains(o); } jaroslav@597: public boolean remove(Object o) { return q.remove(o); } jaroslav@597: public Iterator iterator() { return q.iterator(); } jaroslav@597: public Object[] toArray() { return q.toArray(); } jaroslav@597: public T[] toArray(T[] a) { return q.toArray(a); } jaroslav@597: public String toString() { return q.toString(); } jaroslav@597: public boolean containsAll(Collection c) {return q.containsAll(c);} jaroslav@597: public boolean removeAll(Collection c) {return q.removeAll(c);} jaroslav@597: public boolean retainAll(Collection c) {return q.retainAll(c);} jaroslav@597: // We use inherited addAll; forwarding addAll would be wrong jaroslav@597: } jaroslav@597: }