panda.lang.Collections Maven / Gradle / Ivy
Show all versions of panda-core Show documentation
package panda.lang;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Queue;
import java.util.Random;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import panda.lang.collection.CaseInsensitiveMap;
import panda.lang.collection.CaseInsensitiveSet;
import panda.lang.collection.SafeMap;
@SuppressWarnings({ "rawtypes", "unchecked" })
public abstract class Collections {
/** Constant to avoid repeated object creation */
private static Integer INTEGER_ONE = new Integer(1);
/**
* Clear collection
* @param c collection
*/
public static void clear(Collection> c) {
if (c != null) {
c.clear();
}
}
/**
* Clear map
* @param m map
*/
public static void clear(Map, ?> m) {
if (m != null) {
m.clear();
}
}
/**
* Returns a {@link Collection} containing the union of the given {@link Collection}s.
*
* The cardinality of each element in the returned {@link Collection} will be equal to the
* maximum of the cardinality of that element in the two given {@link Collection}s.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return the union of the two collections
* @see Collection#addAll
*/
public static Collection union(final Collection a, final Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
Iterator it = elts.iterator();
while (it.hasNext()) {
Object obj = it.next();
for (int i = 0, m = Math.max(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a {@link Collection} containing the intersection of the given {@link Collection}s.
*
* The cardinality of each element in the returned {@link Collection} will be equal to the
* minimum of the cardinality of that element in the two given {@link Collection}s.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return the intersection of the two collections
* @see Collection#retainAll
* @see #containsAny
*/
public static Collection intersection(final Collection a, final Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
Iterator it = elts.iterator();
while (it.hasNext()) {
Object obj = it.next();
for (int i = 0, m = Math.min(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a {@link Collection} containing the exclusive disjunction (symmetric difference) of
* the given {@link Collection}s.
*
* The cardinality of each element e in the returned {@link Collection} will be equal to
* max(cardinality(e,a),cardinality(e,b)) - min(cardinality(e,a),cardinality(e,b)).
*
* This is equivalent to
* {@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})
* or
* {@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)}).
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return the symmetric difference of the two collections
*/
public static Collection disjunction(final Collection a, final Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
Iterator it = elts.iterator();
while (it.hasNext()) {
Object obj = it.next();
for (int i = 0, m = ((Math.max(getFreq(obj, mapa), getFreq(obj, mapb))) - (Math.min(
getFreq(obj, mapa), getFreq(obj, mapb)))); i < m; i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a new {@link Collection} containing a - b. The cardinality of
* each element e in the returned {@link Collection} will be the cardinality of e
* in a minus the cardinality of e in b, or zero, whichever is greater.
*
* @param a the collection to subtract from, must not be null
* @param b the collection to subtract, must not be null
* @return a new collection with the results
* @see Collection#removeAll
*/
public static Collection subtract(final Collection a, final Collection b) {
ArrayList list = new ArrayList(a);
for (Iterator it = b.iterator(); it.hasNext();) {
list.remove(it.next());
}
return list;
}
/**
* Returns a {@link Map} mapping each unique element in the given {@link Collection} to an
* {@link Integer} representing the number of occurrences of that element in the
* {@link Collection}.
*
* Only those elements present in the collection will appear as keys in the map.
*
* @param coll the collection to get the cardinality map for, must not be null
* @return the populated cardinality map
*/
public static Map getCardinalityMap(final Collection coll) {
Map count = new HashMap();
for (Iterator it = coll.iterator(); it.hasNext();) {
T obj = it.next();
Integer c = (Integer)(count.get(obj));
if (c == null) {
count.put(obj, INTEGER_ONE);
}
else {
count.put(obj, new Integer(c.intValue() + 1));
}
}
return count;
}
/**
* Returns true iff a is a sub-collection of b, that is, iff the
* cardinality of e in a is less than or equal to the cardinality of e in
* b, for each element e in a.
*
* @param a the first (sub?) collection, must not be null
* @param b the second (super?) collection, must not be null
* @return true
iff a is a sub-collection of b
* @see #isProperSubCollection
* @see Collection#containsAll
*/
public static boolean isSubCollection(final Collection a, final Collection b) {
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Iterator it = a.iterator();
while (it.hasNext()) {
Object obj = it.next();
if (getFreq(obj, mapa) > getFreq(obj, mapb)) {
return false;
}
}
return true;
}
/**
* Returns true iff a is a proper sub-collection of b, that is,
* iff the cardinality of e in a is less than or equal to the cardinality of
* e in b, for each element e in a, and there is at least one
* element f such that the cardinality of f in b is strictly greater than
* the cardinality of f in a.
*
* The implementation assumes
*
* a.size()
and b.size()
represent the total cardinality of
* a and b, resp.
* a.size() < Integer.MAXVALUE
*
*
* @param a the first (sub?) collection, must not be null
* @param b the second (super?) collection, must not be null
* @return true
iff a is a proper sub-collection of b
* @see #isSubCollection
* @see Collection#containsAll
*/
public static boolean isProperSubCollection(final Collection a, final Collection b) {
return (a.size() < b.size()) && Collections.isSubCollection(a, b);
}
/**
* Returns true iff the given {@link Collection}s contain exactly the same elements
* with exactly the same cardinalities.
*
* That is, iff the cardinality of e in a is equal to the cardinality of e
* in b, for each element e in a or b.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return true
iff the collections contain the same elements with the same
* cardinalities.
*/
public static boolean isEqualCollection(final Collection a, final Collection b) {
if (a.size() != b.size()) {
return false;
}
else {
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
if (mapa.size() != mapb.size()) {
return false;
}
else {
Iterator it = mapa.keySet().iterator();
while (it.hasNext()) {
Object obj = it.next();
if (getFreq(obj, mapa) != getFreq(obj, mapb)) {
return false;
}
}
return true;
}
}
}
/**
* Returns the number of occurrences of obj in coll.
*
* @param obj the object to find the cardinality of
* @param coll the collection to search
* @return the the number of occurrences of obj in coll
*/
public static int cardinality(Object obj, final Collection coll) {
if (coll instanceof Set) {
return (coll.contains(obj) ? 1 : 0);
}
int count = 0;
if (obj == null) {
for (Iterator it = coll.iterator(); it.hasNext();) {
if (it.next() == null) {
count++;
}
}
}
else {
for (Iterator it = coll.iterator(); it.hasNext();) {
if (obj.equals(it.next())) {
count++;
}
}
}
return count;
}
// -----------------------------------------------------------------------
/**
* Adds an element to the collection unless the element is null.
*
* @param collection the collection to add to, must not be null
* @param object the object to add, if null it will not be added
* @return true if the collection changed
* @throws NullPointerException if the collection is null
*/
public static boolean addIgnoreNull(Collection collection, Object object) {
return (object == null ? false : collection.add(object));
}
/**
* Adds all elements in the iteration to the given collection.
*
* @param collection the collection to add to, must not be null
* @param iterator the iterator of elements to add, must not be null
* @throws NullPointerException if the collection or iterator is null
*/
public static void addAll(Collection collection, Iterator iterator) {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
}
/**
* Adds all elements in the enumeration to the given collection.
*
* @param collection the collection to add to, must not be null
* @param enumeration the enumeration of elements to add, must not be null
* @throws NullPointerException if the collection or enumeration is null
*/
public static void addAll(Collection collection, Enumeration enumeration) {
while (enumeration.hasMoreElements()) {
collection.add(enumeration.nextElement());
}
}
public static void insert(List list, int index, Object value) {
if (index < 0 || index >= list.size()) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + list.size());
}
list.add(null);
for (int i = list.size() - 1; i > index; i--) {
list.set(i, list.get(i - 1));
}
list.set(index, value);
}
/**
* return first key of map
* @param map the map
* @return first key
*/
public static K firstKey(Map map) {
if (isEmpty(map)) {
return null;
}
return map.keySet().iterator().next();
}
/**
* return first value of map
* @param map the map
* @return first value
*/
public static V firstValue(Map, V> map) {
if (isEmpty(map)) {
return null;
}
return map.values().iterator().next();
}
/**
* return first entry of map
* @param map the map
* @return first entry
*/
public static Entry firstEntry(Map map) {
if (isEmpty(map)) {
return null;
}
return map.entrySet().iterator().next();
}
// -----------------------------------------------------------------------
/**
* Null-safe check if the specified collection is empty.
*
* Null returns true.
*
* @param coll the collection to check, may be null
* @return true if empty or null
*/
public static boolean isEmpty(Collection coll) {
return (coll == null || coll.isEmpty());
}
/**
* Null-safe check if the specified collection is not empty.
*
* Null returns false.
*
* @param coll the collection to check, may be null
* @return true if non-null and non-empty
*/
public static boolean isNotEmpty(Collection coll) {
return !Collections.isEmpty(coll);
}
// -----------------------------------------------------------------------
private static final int getFreq(final Object obj, final Map freqMap) {
Integer count = (Integer)freqMap.get(obj);
if (count != null) {
return count.intValue();
}
return 0;
}
// -----------------------------------------------------------------------
/**
* Returns a collection containing all the elements in collection
that are also in
* retain
. The cardinality of an element e
in the returned collection
* is the same as the cardinality of e
in collection
unless
* retain
does not contain e
, in which case the cardinality is zero.
* This method is useful if you do not wish to modify the collection c
and thus
* cannot call c.retainAll(retain);
.
*
* @param collection the collection whose contents are the target of the #retailAll operation
* @param retain the collection containing the elements to be retained in the returned
* collection
* @return a Collection
containing all the elements of collection
that
* occur at least once in retain
.
* @throws NullPointerException if either parameter is null
*/
public static Collection retainAll(Collection collection, Collection retain) {
List list = new ArrayList(Math.min(collection.size(), retain.size()));
for (Iterator iter = collection.iterator(); iter.hasNext();) {
Object obj = iter.next();
if (retain.contains(obj)) {
list.add(obj);
}
}
return list;
}
/**
* Removes the elements in remove
from collection
. That is, this
* method returns a collection containing all the elements in c
that are not in
* remove
. The cardinality of an element e
in the returned collection
* is the same as the cardinality of e
in collection
unless
* remove
contains e
, in which case the cardinality is zero. This
* method is useful if you do not wish to modify the collection c
and thus cannot
* call collection.removeAll(remove);
.
*
* @param collection the collection from which items are removed (in the returned collection)
* @param remove the items to be removed from the returned collection
* @return a Collection
containing all the elements of collection
* except any elements that also occur in remove
.
* @throws NullPointerException if either parameter is null
*/
public static Collection removeAll(Collection collection, Collection remove) {
List list = new ArrayList();
for (Iterator iter = collection.iterator(); iter.hasNext();) {
Object obj = iter.next();
if (remove.contains(obj) == false) {
list.add(obj);
}
}
return list;
}
/**
* @param set the Set to wrap
* @return a case insensitive set
*/
public static Set caseInsensitiveSet(Collection extends E> set) {
return new CaseInsensitiveSet(set);
}
/**
* @param map the Map to wrap
* @return a case insensitive map
*/
public static Map caseInsensitiveMap(Map map) {
return new CaseInsensitiveMap(map);
}
/**
* @param map the Map to wrap
* @return a safe map
*/
public static Map safeMap(Map map) {
return new SafeMap(map);
}
/**
* Return true
if the supplied Map is null
or empty. Otherwise, return
* false
.
*
* @param map the Map to check
* @return whether the given Map is empty
*/
public static boolean isEmpty(Map map) {
return (map == null || map.isEmpty());
}
/**
* Return true
if the supplied Map is not null
or empty. Otherwise,
* return false
.
*
* @param map the Map to check
* @return whether the given Map is not empty
*/
public static boolean isNotEmpty(Map map) {
return (map != null && !map.isEmpty());
}
/**
* Remove null elements in the collection.
*
* @param collection the collection to get the input from, may be null
*/
public static void removeNull(Collection collection) {
if (collection != null) {
for (Iterator it = collection.iterator(); it.hasNext();) {
if (it.next() == null) {
it.remove();
}
}
}
}
/**
* Remove null elements in the map.
*
* @param map the map to get the input from, may be null
*/
public static void removeNull(Map map) {
if (map != null) {
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
if (((Entry)it.next()).getValue() == null) {
it.remove();
}
}
}
}
/**
* Remove null elements in the collection.
*
* @param collection the collection to get the input from, may be null
* @return null elements removed collection
* @throws IllegalAccessException Class.newInstance
* @throws InstantiationException Class.newInstance
*/
public static Collection copyNotNull(Collection collection) throws InstantiationException,
IllegalAccessException {
if (collection == null) {
return null;
}
Collection nc = collection.getClass().newInstance();
for (Iterator it = collection.iterator(); it.hasNext();) {
Object o = it.next();
if (o != null) {
nc.add(o);
}
}
return nc;
}
/**
* Merge the given array into the given Collection.
*
* @param array the array to merge (may be null
)
* @param collection the target Collection to merge the array into
*/
public static void mergeArrayIntoCollection(Object array, Collection collection) {
if (collection == null) {
throw new IllegalArgumentException("Collection must not be null");
}
Object[] arr = Arrays.toObjectArray(array);
for (int i = 0; i < arr.length; i++) {
collection.add(arr[i]);
}
}
/**
* Merge the given Properties instance into the given Map, copying all properties (key-value
* pairs) over.
*
* Uses Properties.propertyNames()
to even catch default properties linked into the
* original Properties instance.
*
* @param props the Properties instance to merge (may be null
)
* @param map the target Map to merge the properties into
*/
public static void mergePropertiesIntoMap(Properties props, Map map) {
if (map == null) {
throw new IllegalArgumentException("Map must not be null");
}
if (props != null) {
for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
String key = (String)en.nextElement();
map.put(key, props.getProperty(key));
}
}
}
/**
* Check whether the given Iterator contains the given element.
*
* @param iterator the Iterator to check
* @param element the element to look for
* @return true
if found, false
else
*/
public static boolean contains(Iterator iterator, Object element) {
if (iterator != null) {
while (iterator.hasNext()) {
Object candidate = iterator.next();
if (Objects.nullSafeEquals(candidate, element)) {
return true;
}
}
}
return false;
}
/**
* Returns true if this map contains a mapping for the specified key. More formally,
* returns true if and only if this map contains a mapping for a key k such
* that (key==null ? k==null : key.equals(k)). (There can be at most one such mapping.)
*
* @param map the map
* @param key key whose presence in this map is to be tested
* @return true if this map contains a mapping for the specified key
* @throws ClassCastException if the key is of an inappropriate type for this map
* (optional)
* @throws NullPointerException if the specified key is null and this map does not permit null
* keys (optional)
*/
public static boolean containsKey(Map map, Object key) {
if (map != null) {
return map.containsKey(key);
}
return false;
}
/**
* Check whether the given Iterator contains the given element.
*
* @param source the source collection
* @param element the element to look for
* @return true
if found, false
else
*/
public static boolean contains(Collection source, Object element) {
if (source != null) {
return source.contains(element);
}
return false;
}
/**
* Check whether the given Enumeration contains the given element.
*
* @param enumeration the Enumeration to check
* @param element the element to look for
* @return true
if found, false
else
*/
public static boolean contains(Enumeration enumeration, Object element) {
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
Object candidate = enumeration.nextElement();
if (Objects.nullSafeEquals(candidate, element)) {
return true;
}
}
}
return false;
}
/**
* Check whether the given Collection contains the given element instance.
*
* Enforces the given instance to be present, rather than returning true
for an
* equal element as well.
*
* @param collection the Collection to check
* @param element the element to look for
* @return true
if found, false
else
*/
public static boolean containsInstance(Collection collection, Object element) {
if (collection != null) {
for (Iterator it = collection.iterator(); it.hasNext();) {
Object candidate = it.next();
if (candidate == element) {
return true;
}
}
}
return false;
}
/**
* Return true
if any element in 'candidates
' is contained in '
* source
'; otherwise returns false
.
*
* @param source the source Collection
* @param candidates the candidates to search for
* @return whether any of the candidates has been found
*/
public static boolean containsAny(Collection source, Collection candidates) {
if (isEmpty(source) || isEmpty(candidates)) {
return false;
}
for (Iterator it = candidates.iterator(); it.hasNext();) {
if (source.contains(it.next())) {
return true;
}
}
return false;
}
/**
* Return the first element in 'candidates
' that is contained in '
* source
'. If no element in 'candidates
' is present in '
* source
' returns null
. Iteration order is {@link Collection}
* implementation specific.
*
* @param source the source Collection
* @param candidates the candidates to search for
* @return the first present object, or null
if not found
*/
public static Object findFirstMatch(Collection source, Collection candidates) {
if (isEmpty(source) || isEmpty(candidates)) {
return null;
}
for (Iterator it = candidates.iterator(); it.hasNext();) {
Object candidate = it.next();
if (source.contains(candidate)) {
return candidate;
}
}
return null;
}
/**
* Find a single value of the given type in the given Collection.
*
* @param collection the Collection to search
* @param type the type to look for
* @return a value of the given type found if there is a clear match, or null
if
* none or more than one such value found
*/
public static Object findValueOfType(Collection collection, Class type) {
if (isEmpty(collection)) {
return null;
}
Object value = null;
for (Iterator it = collection.iterator(); it.hasNext();) {
Object obj = it.next();
if (type == null || type.isInstance(obj)) {
if (value != null) {
// More than one value found... no clear single value.
return null;
}
value = obj;
}
}
return value;
}
/**
* Find a single value of one of the given types in the given Collection: searching the
* Collection for a value of the first type, then searching for a value of the second type, etc.
*
* @param collection the collection to search
* @param types the types to look for, in prioritized order
* @return a value of one of the given types found if there is a clear match, or
* null
if none or more than one such value found
*/
public static Object findValueOfType(Collection collection, Class[] types) {
if (isEmpty(collection) || Arrays.isEmpty(types)) {
return null;
}
for (int i = 0; i < types.length; i++) {
Object value = findValueOfType(collection, types[i]);
if (value != null) {
return value;
}
}
return null;
}
/**
* Determine whether the given Collection only contains a single unique object.
*
* @param collection the Collection to check
* @return true
if the collection contains a single reference or multiple
* references to the same instance, false
else
*/
public static boolean hasUniqueObject(Collection collection) {
if (isEmpty(collection)) {
return false;
}
boolean hasCandidate = false;
Object candidate = null;
for (Iterator it = collection.iterator(); it.hasNext();) {
Object elem = it.next();
if (!hasCandidate) {
hasCandidate = true;
candidate = elem;
}
else if (candidate != elem) {
return false;
}
}
return true;
}
//--------------------------------------------------------
// @see java.util.Collections
/**
* Sorts the specified list into ascending order, according to the natural ordering of
* its elements. All elements in the list must implement the Comparable interface.
* Furthermore, all elements in the list must be mutually comparable (that is,
* e1.compareTo(e2) must not throw a ClassCastException for any elements
* e1 and e2 in the list).
*
* This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort.
*
* The specified list must be modifiable, but need not be resizable.
*
* The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest
* element in the low sublist is less than the lowest element in the high sublist). This
* algorithm offers guaranteed n log(n) performance. This implementation dumps the specified
* list into an array, sorts the array, and iterates over the list resetting each element from
* the corresponding position in the array. This avoids the n2 log(n) performance
* that would result from attempting to sort a linked list in place.
*
* @param list the list to be sorted.
* @throws ClassCastException if the list contains elements that are not mutually
* comparable (for example, strings and integers).
* @throws UnsupportedOperationException if the specified list's list-iterator does not support
* the set operation.
* @see Comparable
*/
public static > void sort(List list) {
java.util.Collections.sort(list);
}
/**
* Sorts the specified list according to the order induced by the specified comparator. All
* elements in the list must be mutually comparable using the specified comparator (that
* is, c.compare(e1, e2) must not throw a ClassCastException for any elements
* e1 and e2 in the list).
*
* This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort.
*
* The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest
* element in the low sublist is less than the lowest element in the high sublist). This
* algorithm offers guaranteed n log(n) performance. The specified list must be modifiable, but
* need not be resizable. This implementation dumps the specified list into an array, sorts the
* array, and iterates over the list resetting each element from the corresponding position in
* the array. This avoids the n2 log(n) performance that would result from attempting
* to sort a linked list in place.
*
* @param list the list to be sorted.
* @param c the comparator to determine the order of the list. A null value indicates
* that the elements' natural ordering should be used.
* @throws ClassCastException if the list contains elements that are not mutually
* comparable using the specified comparator.
* @throws UnsupportedOperationException if the specified list's list-iterator does not support
* the set operation.
* @see Comparator
*/
public static void sort(List list, Comparator super T> c) {
java.util.Collections.sort(list, c);
}
/**
* Searches the specified list for the specified object using the binary search algorithm. The
* list must be sorted into ascending order according to the {@linkplain Comparable natural
* ordering} of its elements (as by the {@link #sort(List)} method) prior to making this call.
* If it is not sorted, the results are undefined. If the list contains multiple elements equal
* to the specified object, there is no guarantee which one will be found.
*
* This method runs in log(n) time for a "random access" list (which provides near-constant-time
* positional access). If the specified list does not implement the {@link RandomAccess}
* interface and is large, this method will do an iterator-based binary search that performs
* O(n) link traversals and O(log n) element comparisons.
*
* @param list the list to be searched.
* @param key the key to be searched for.
* @return the index of the search key, if it is contained in the list; otherwise,
* (-(insertion point) - 1). The insertion point is defined as
* the point at which the key would be inserted into the list: the index of the first
* element greater than the key, or list.size() if all elements in the list are
* less than the specified key. Note that this guarantees that the return value will be
* >= 0 if and only if the key is found.
* @throws ClassCastException if the list contains elements that are not mutually
* comparable (for example, strings and integers), or the search key is not
* mutually comparable with the elements of the list.
*/
public static int binarySearch(List extends Comparable super T>> list, T key) {
return java.util.Collections.binarySearch(list, key);
}
/**
* Searches the specified list for the specified object using the binary search algorithm. The
* list must be sorted into ascending order according to the specified comparator (as by the
* {@link #sort(List, Comparator) sort(List, Comparator)} method), prior to making this call. If
* it is not sorted, the results are undefined. If the list contains multiple elements equal to
* the specified object, there is no guarantee which one will be found.
*
* This method runs in log(n) time for a "random access" list (which provides near-constant-time
* positional access). If the specified list does not implement the {@link RandomAccess}
* interface and is large, this method will do an iterator-based binary search that performs
* O(n) link traversals and O(log n) element comparisons.
*
* @param list the list to be searched.
* @param key the key to be searched for.
* @param c the comparator by which the list is ordered. A null value indicates that
* the elements' {@linkplain Comparable natural ordering} should be used.
* @return the index of the search key, if it is contained in the list; otherwise,
* (-(insertion point) - 1). The insertion point is defined as
* the point at which the key would be inserted into the list: the index of the first
* element greater than the key, or list.size() if all elements in the list are
* less than the specified key. Note that this guarantees that the return value will be
* >= 0 if and only if the key is found.
* @throws ClassCastException if the list contains elements that are not mutually
* comparable using the specified comparator, or the search key is not mutually
* comparable with the elements of the list using this comparator.
*/
public static int binarySearch(List extends T> list, T key, Comparator super T> c) {
return java.util.Collections.binarySearch(list, key, c);
}
/**
* Reverses the order of the elements in the specified list.
*
* This method runs in linear time.
*
* @param list the list whose elements are to be reversed.
* @throws UnsupportedOperationException if the specified list or its list-iterator does not
* support the set operation.
*/
public static void reverse(List> list) {
java.util.Collections.reverse(list);
}
/**
* Randomly permutes the specified list using a default source of randomness. All permutations
* occur with approximately equal likelihood.
*
* The hedge "approximately" is used in the foregoing description because default source of
* randomness is only approximately an unbiased source of independently chosen bits. If it were
* a perfect source of randomly chosen bits, then the algorithm would choose permutations with
* perfect uniformity.
*
* This implementation traverses the list backwards, from the last element up to the second,
* repeatedly swapping a randomly selected element into the "current position". Elements are
* randomly selected from the portion of the list that runs from the first element to the
* current position, inclusive.
*
* This method runs in linear time. If the specified list does not implement the
* {@link RandomAccess} interface and is large, this implementation dumps the specified list
* into an array before shuffling it, and dumps the shuffled array back into the list. This
* avoids the quadratic behavior that would result from shuffling a "sequential access" list in
* place.
*
* @param list the list to be shuffled.
* @throws UnsupportedOperationException if the specified list or its list-iterator does not
* support the set operation.
*/
public static void shuffle(List> list) {
java.util.Collections.shuffle(list);
}
/**
* Randomly permute the specified list using the specified source of randomness. All
* permutations occur with equal likelihood assuming that the source of randomness is fair.
*
* This implementation traverses the list backwards, from the last element up to the second,
* repeatedly swapping a randomly selected element into the "current position". Elements are
* randomly selected from the portion of the list that runs from the first element to the
* current position, inclusive.
*
* This method runs in linear time. If the specified list does not implement the
* {@link RandomAccess} interface and is large, this implementation dumps the specified list
* into an array before shuffling it, and dumps the shuffled array back into the list. This
* avoids the quadratic behavior that would result from shuffling a "sequential access" list in
* place.
*
* @param list the list to be shuffled.
* @param rnd the source of randomness to use to shuffle the list.
* @throws UnsupportedOperationException if the specified list or its list-iterator does not
* support the set operation.
*/
public static void shuffle(List> list, Random rnd) {
java.util.Collections.shuffle(list, rnd);
}
/**
* Swaps the elements at the specified positions in the specified list. (If the specified
* positions are equal, invoking this method leaves the list unchanged.)
*
* @param list The list in which to swap elements.
* @param i the index of one element to be swapped.
* @param j the index of the other element to be swapped.
* @throws IndexOutOfBoundsException if either i or j is out of range (i <
* 0 || i >= list.size() || j < 0 || j >= list.size()).
*/
public static void swap(List> list, int i, int j) {
java.util.Collections.swap(list, i, j);
}
/**
* Swaps the key and value of the map.
* Map -> Map
*
* @param map the map
*/
public static void swap(Map, ?> map) {
if (isEmpty(map)) {
return;
}
Map nm = new HashMap();
for (Entry en : map.entrySet()) {
nm.put(en.getValue(), en.getKey());
}
map.clear();
map.putAll(nm);
}
/**
* Replaces all of the elements of the specified list with the specified element.
*
* This method runs in linear time.
*
* @param list the list to be filled with the specified element.
* @param obj The element with which to fill the specified list.
* @throws UnsupportedOperationException if the specified list or its list-iterator does not
* support the set operation.
*/
public static void fill(List super T> list, T obj) {
java.util.Collections.fill(list, obj);
}
/**
* Copies all of the elements from one list into another. After the operation, the index of each
* copied element in the destination list will be identical to its index in the source list. The
* destination list must be at least as long as the source list. If it is longer, the remaining
* elements in the destination list are unaffected.
*
* This method runs in linear time.
*
* @param dest The destination list.
* @param src The source list.
* @throws IndexOutOfBoundsException if the destination list is too small to contain the entire
* source List.
* @throws UnsupportedOperationException if the destination list's list-iterator does not
* support the set operation.
*/
public static void copy(List super T> dest, List extends T> src) {
java.util.Collections.copy(dest, src);
}
private final static int COPY_THRESHOLD = 10;
/**
* @param src the source list.
* @param srcPos starting position in the source list.
* @param des the destination list.
* @param desPos starting position in the destination data.
* @param length the number of list elements to be copied.
*/
public static void copy(List extends T> src, int srcPos, List super T> des, int desPos, int length) {
Asserts.isTrue(srcPos >= 0, "The srcPos value must be greater or equal zero: %d", srcPos);
Asserts.isTrue(desPos >= 0, "The desPos value must be greater or equal zero: %d", desPos);
int srcSize = src.size();
int desSize = des.size();
Asserts.isTrue(srcPos + length <= srcSize && desPos + length <= desSize,
"The length value is out of bounds: %d", length);
if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && des instanceof RandomAccess)) {
for (int i = 0; i < length; i++) {
des.set(desPos + i, src.get(srcPos + i));
}
}
else {
ListIterator super T> di = des.listIterator();
ListIterator extends T> si = src.listIterator();
for (int i = 0; i < srcPos; i++) {
si.next();
}
for (int i = 0; i < desPos; i++) {
di.next();
}
for (int i = 0; i < length; i++) {
di.next();
di.set(si.next());
}
}
}
/**
* Returns the minimum element of the given collection, according to the natural ordering
* of its elements. All elements in the collection must implement the Comparable
* interface. Furthermore, all elements in the collection must be mutually comparable
* (that is, e1.compareTo(e2) must not throw a ClassCastException for any
* elements e1 and e2 in the collection).
*
* This method iterates over the entire collection, hence it requires time proportional to the
* size of the collection.
*
* @param coll the collection whose minimum element is to be determined.
* @return the minimum element of the given collection, according to the natural ordering
* of its elements.
* @throws ClassCastException if the collection contains elements that are not mutually
* comparable (for example, strings and integers).
* @throws NoSuchElementException if the collection is empty.
* @see Comparable
*/
public static > T min(Collection extends T> coll) {
return java.util.Collections.min(coll);
}
/**
* Returns the minimum element of the given collection, according to the order induced by the
* specified comparator. All elements in the collection must be mutually comparable by
* the specified comparator (that is, comp.compare(e1, e2) must not throw a
* ClassCastException for any elements e1 and e2 in the collection).
*
* This method iterates over the entire collection, hence it requires time proportional to the
* size of the collection.
*
* @param coll the collection whose minimum element is to be determined.
* @param comp the comparator with which to determine the minimum element. A null value
* indicates that the elements' natural ordering should be used.
* @return the minimum element of the given collection, according to the specified comparator.
* @throws ClassCastException if the collection contains elements that are not mutually
* comparable using the specified comparator.
* @throws NoSuchElementException if the collection is empty.
* @see Comparable
*/
public static T min(Collection extends T> coll, Comparator super T> comp) {
return java.util.Collections.min(coll, comp);
}
/**
* Returns the maximum element of the given collection, according to the natural ordering
* of its elements. All elements in the collection must implement the Comparable
* interface. Furthermore, all elements in the collection must be mutually comparable
* (that is, e1.compareTo(e2) must not throw a ClassCastException for any
* elements e1 and e2 in the collection).
*
* This method iterates over the entire collection, hence it requires time proportional to the
* size of the collection.
*
* @param coll the collection whose maximum element is to be determined.
* @return the maximum element of the given collection, according to the natural ordering
* of its elements.
* @throws ClassCastException if the collection contains elements that are not mutually
* comparable (for example, strings and integers).
* @throws NoSuchElementException if the collection is empty.
* @see Comparable
*/
public static > T max(Collection extends T> coll) {
return java.util.Collections.max(coll);
}
/**
* Returns the maximum element of the given collection, according to the order induced by the
* specified comparator. All elements in the collection must be mutually comparable by
* the specified comparator (that is, comp.compare(e1, e2) must not throw a
* ClassCastException for any elements e1 and e2 in the collection).
*
* This method iterates over the entire collection, hence it requires time proportional to the
* size of the collection.
*
* @param coll the collection whose maximum element is to be determined.
* @param comp the comparator with which to determine the maximum element. A null value
* indicates that the elements' natural ordering should be used.
* @return the maximum element of the given collection, according to the specified comparator.
* @throws ClassCastException if the collection contains elements that are not mutually
* comparable using the specified comparator.
* @throws NoSuchElementException if the collection is empty.
* @see Comparable
*/
public static T max(Collection extends T> coll, Comparator super T> comp) {
return java.util.Collections.max(coll, comp);
}
/**
* Rotates the elements in the specified list by the specified distance. After calling this
* method, the element at index i will be the element previously at index
* (i - distance) mod list.size(), for all values of i between
* 0 and list.size()-1, inclusive. (This method has no effect on the size of
* the list.)
*
* For example, suppose list comprises [t, a, n, k, s]. After invoking
* Collections.rotate(list, 1) (or Collections.rotate(list, -4)),
* list will comprise [s, t, a, n, k].
*
* Note that this method can usefully be applied to sublists to move one or more elements within
* a list while preserving the order of the remaining elements. For example, the following idiom
* moves the element at index j forward to position k (which must be greater
* than or equal to j):
*
*
* Collections.rotate(list.subList(j, k + 1), -1);
*
*
* To make this concrete, suppose list comprises [a, b, c, d, e]. To move the
* element at index 1 (b) forward two positions, perform the following
* invocation:
*
*
* Collections.rotate(l.subList(1, 4), -1);
*
*
* The resulting list is [a, c, d, b, e].
*
* To move more than one element forward, increase the absolute value of the rotation distance.
* To move elements backward, use a positive shift distance.
*
* If the specified list is small or implements the {@link RandomAccess} interface, this
* implementation exchanges the first element into the location it should go, and then
* repeatedly exchanges the displaced element into the location it should go until a displaced
* element is swapped into the first element. If necessary, the process is repeated on the
* second and successive elements, until the rotation is complete. If the specified list is
* large and doesn't implement the RandomAccess interface, this implementation breaks
* the list into two sublist views around index -distance mod size. Then the
* {@link #reverse(List)} method is invoked on each sublist view, and finally it is invoked on
* the entire list. For a more complete description of both algorithms, see Section 2.3 of Jon
* Bentley's Programming Pearls (Addison-Wesley, 1986).
*
* @param list the list to be rotated.
* @param distance the distance to rotate the list. There are no constraints on this value; it
* may be zero, negative, or greater than list.size().
* @throws UnsupportedOperationException if the specified list or its list-iterator does not
* support the set operation.
*/
public static void rotate(List> list, int distance) {
java.util.Collections.rotate(list, distance);
}
/**
* Replaces all occurrences of one specified value in a list with another. More formally,
* replaces with newVal each element e in list such that
* (oldVal==null ? e==null : oldVal.equals(e)). (This method has no effect on the size
* of the list.)
*
* @param list the list in which replacement is to occur.
* @param oldVal the old value to be replaced.
* @param newVal the new value with which oldVal is to be replaced.
* @return true if list contained one or more elements e such that
* (oldVal==null ? e==null : oldVal.equals(e)).
* @throws UnsupportedOperationException if the specified list or its list-iterator does not
* support the set operation.
*/
public static boolean replaceAll(List list, T oldVal, T newVal) {
return java.util.Collections.replaceAll(list, oldVal, newVal);
}
/**
* Returns the starting position of the first occurrence of the specified target list within the
* specified source list, or -1 if there is no such occurrence. More formally, returns the
* lowest index i such that source.subList(i, i+target.size()).equals(target),
* or -1 if there is no such index. (Returns -1 if target.size() > source.size().)
*
* This implementation uses the "brute force" technique of scanning over the source list,
* looking for a match with the target at each location in turn.
*
* @param source the list in which to search for the first occurrence of target.
* @param target the list to search for as a subList of source.
* @return the starting position of the first occurrence of the specified target list within the
* specified source list, or -1 if there is no such occurrence.
*/
public static int indexOfSubList(List> source, List> target) {
return java.util.Collections.indexOfSubList(source, target);
}
/**
* Returns the starting position of the last occurrence of the specified target list within the
* specified source list, or -1 if there is no such occurrence. More formally, returns the
* highest index i such that source.subList(i, i+target.size()).equals(target)
* , or -1 if there is no such index. (Returns -1 if target.size() > source.size().)
*
* This implementation uses the "brute force" technique of iterating over the source list,
* looking for a match with the target at each location in turn.
*
* @param source the list in which to search for the last occurrence of target.
* @param target the list to search for as a subList of source.
* @return the starting position of the last occurrence of the specified target list within the
* specified source list, or -1 if there is no such occurrence.
*/
public static int lastIndexOfSubList(List> source, List> target) {
return java.util.Collections.lastIndexOfSubList(source, target);
}
// Unmodifiable Wrappers
/**
* Returns an unmodifiable view of the specified collection. This method allows modules to
* provide users with "read-only" access to internal collections. Query operations on the
* returned collection "read through" to the specified collection, and attempts to modify the
* returned collection, whether direct or via its iterator, result in an
* UnsupportedOperationException.
*
* The returned collection does not pass the hashCode and equals operations through to
* the backing collection, but relies on Object's equals and hashCode
* methods. This is necessary to preserve the contracts of these operations in the case that the
* backing collection is a set or a list.
*
* The returned collection will be serializable if the specified collection is serializable.
*
* @param c the collection for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified collection.
*/
public static Collection unmodifiableCollection(Collection extends T> c) {
if (c == null) {
return null;
}
return java.util.Collections.unmodifiableCollection(c);
}
/**
* Returns an unmodifiable view of the specified set. This method allows modules to provide
* users with "read-only" access to internal sets. Query operations on the returned set
* "read through" to the specified set, and attempts to modify the returned set, whether direct
* or via its iterator, result in an UnsupportedOperationException.
*
* The returned set will be serializable if the specified set is serializable.
*
* @param s the set for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified set.
*/
public static Set unmodifiableSet(Set extends T> s) {
if (s == null) {
return null;
}
return java.util.Collections.unmodifiableSet(s);
}
/**
* Returns an unmodifiable view of the specified sorted set. This method allows modules to
* provide users with "read-only" access to internal sorted sets. Query operations on the
* returned sorted set "read through" to the specified sorted set. Attempts to modify the
* returned sorted set, whether direct, via its iterator, or via its subSet,
* headSet, or tailSet views, result in an
* UnsupportedOperationException.
*
* The returned sorted set will be serializable if the specified sorted set is serializable.
*
* @param s the sorted set for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified sorted set.
*/
public static SortedSet unmodifiableSortedSet(SortedSet s) {
if (s == null) {
return null;
}
return java.util.Collections.unmodifiableSortedSet(s);
}
/**
* Returns an unmodifiable view of the specified list. This method allows modules to provide
* users with "read-only" access to internal lists. Query operations on the returned list
* "read through" to the specified list, and attempts to modify the returned list, whether
* direct or via its iterator, result in an UnsupportedOperationException.
*
* The returned list will be serializable if the specified list is serializable. Similarly, the
* returned list will implement {@link RandomAccess} if the specified list does.
*
* @param list the list for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified list.
*/
public static List unmodifiableList(List extends T> list) {
if (list == null) {
return null;
}
return java.util.Collections.unmodifiableList(list);
}
/**
* Returns an unmodifiable view of the specified map. This method allows modules to provide
* users with "read-only" access to internal maps. Query operations on the returned map
* "read through" to the specified map, and attempts to modify the returned map, whether direct
* or via its collection views, result in an UnsupportedOperationException.
*
* The returned map will be serializable if the specified map is serializable.
*
* @param m the map for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified map.
*/
public static Map unmodifiableMap(Map extends K, ? extends V> m) {
if (m == null) {
return null;
}
return java.util.Collections.unmodifiableMap(m);
}
/**
* Returns an unmodifiable view of the specified sorted map. This method allows modules to
* provide users with "read-only" access to internal sorted maps. Query operations on the
* returned sorted map "read through" to the specified sorted map. Attempts to modify the
* returned sorted map, whether direct, via its collection views, or via its subMap,
* headMap, or tailMap views, result in an
* UnsupportedOperationException.
*
* The returned sorted map will be serializable if the specified sorted map is serializable.
*
* @param m the sorted map for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified sorted map.
*/
public static SortedMap unmodifiableSortedMap(SortedMap m) {
if (m == null) {
return null;
}
return java.util.Collections.unmodifiableSortedMap(m);
}
/**
* Returns a synchronized (thread-safe) collection backed by the specified collection. In order
* to guarantee serial access, it is critical that all access to the backing
* collection is accomplished through the returned collection.
*
* It is imperative that the user manually synchronize on the returned collection when iterating
* over it:
*
*
* Collection c = java.util.Collections.synchronizedCollection(myCollection);
* ...
* synchronized(c) {
* Iterator i = c.iterator(); // Must be in the synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned collection does not pass the hashCode and equals
* operations through to the backing collection, but relies on Object's equals and
* hashCode methods. This is necessary to preserve the contracts of these operations in the case
* that the backing collection is a set or a list.
*
* The returned collection will be serializable if the specified collection is serializable.
*
* @param c the collection to be "wrapped" in a synchronized collection.
* @return a synchronized view of the specified collection.
*/
public static Collection synchronizedCollection(Collection c) {
if (c == null) {
return null;
}
return java.util.Collections.synchronizedCollection(c);
}
/**
* Returns a synchronized (thread-safe) set backed by the specified set. In order to guarantee
* serial access, it is critical that all access to the backing set is
* accomplished through the returned set.
*
* It is imperative that the user manually synchronize on the returned set when iterating over
* it:
*
*
* Set s = java.util.Collections.synchronizedSet(new HashSet());
* ...
* synchronized(s) {
* Iterator i = s.iterator(); // Must be in the synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned set will be serializable if the specified set is serializable.
*
* @param s the set to be "wrapped" in a synchronized set.
* @return a synchronized view of the specified set.
*/
public static Set synchronizedSet(Set s) {
if (s == null) {
return null;
}
return java.util.Collections.synchronizedSet(s);
}
/**
* Returns a synchronized (thread-safe) sorted set backed by the specified sorted set. In order
* to guarantee serial access, it is critical that all access to the backing
* sorted set is accomplished through the returned sorted set (or its views).
*
* It is imperative that the user manually synchronize on the returned sorted set when iterating
* over it or any of its subSet, headSet, or tailSet views.
*
*
* SortedSet s = java.util.Collections.synchronizedSortedSet(new TreeSet());
* ...
* synchronized(s) {
* Iterator i = s.iterator(); // Must be in the synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* or:
*
*
* SortedSet s = java.util.Collections.synchronizedSortedSet(new TreeSet());
* SortedSet s2 = s.headSet(foo);
* ...
* synchronized(s) { // Note: s, not s2!!!
* Iterator i = s2.iterator(); // Must be in the synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned sorted set will be serializable if the specified sorted set is serializable.
*
* @param s the sorted set to be "wrapped" in a synchronized sorted set.
* @return a synchronized view of the specified sorted set.
*/
public static SortedSet synchronizedSortedSet(SortedSet s) {
if (s == null) {
return null;
}
return java.util.Collections.synchronizedSortedSet(s);
}
/**
* Returns a synchronized (thread-safe) list backed by the specified list. In order to guarantee
* serial access, it is critical that all access to the backing list is
* accomplished through the returned list.
*
* It is imperative that the user manually synchronize on the returned list when iterating over
* it:
*
*
* List list = java.util.Collections.synchronizedList(new ArrayList());
* ...
* synchronized(list) {
* Iterator i = list.iterator(); // Must be in synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned list will be serializable if the specified list is serializable.
*
* @param list the list to be "wrapped" in a synchronized list.
* @return a synchronized view of the specified list.
*/
public static List synchronizedList(List list) {
if (list == null) {
return null;
}
return java.util.Collections.synchronizedList(list);
}
/**
* Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee
* serial access, it is critical that all access to the backing map is
* accomplished through the returned map.
*
* It is imperative that the user manually synchronize on the returned map when iterating over
* any of its collection views:
*
*
* Map m = java.util.Collections.synchronizedMap(new HashMap());
* ...
* Set s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized(m) { // Synchronizing on m, not s!
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned map will be serializable if the specified map is serializable.
*
* @param m the map to be "wrapped" in a synchronized map.
* @return a synchronized view of the specified map.
*/
public static Map synchronizedMap(Map m) {
if (m == null) {
return null;
}
return java.util.Collections.synchronizedMap(m);
}
/**
* Returns a synchronized (thread-safe) sorted map backed by the specified sorted map. In order
* to guarantee serial access, it is critical that all access to the backing
* sorted map is accomplished through the returned sorted map (or its views).
*
* It is imperative that the user manually synchronize on the returned sorted map when iterating
* over any of its collection views, or the collections views of any of its subMap,
* headMap or tailMap views.
*
*
* SortedMap m = java.util.Collections.synchronizedSortedMap(new TreeMap());
* ...
* Set s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized(m) { // Synchronizing on m, not s!
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* or:
*
*
* SortedMap m = java.util.Collections.synchronizedSortedMap(new TreeMap());
* SortedMap m2 = m.subMap(foo, bar);
* ...
* Set s2 = m2.keySet(); // Needn't be in synchronized block
* ...
* synchronized(m) { // Synchronizing on m, not m2 or s2!
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext())
* foo(i.next());
* }
*
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned sorted map will be serializable if the specified sorted map is serializable.
*
* @param m the sorted map to be "wrapped" in a synchronized sorted map.
* @return a synchronized view of the specified sorted map.
*/
public static SortedMap synchronizedSortedMap(SortedMap m) {
if (m == null) {
return null;
}
return java.util.Collections.synchronizedSortedMap(m);
}
/**
* Returns a dynamically typesafe view of the specified collection. Any attempt to insert an
* element of the wrong type will result in an immediate ClassCastException. Assuming a
* collection contains no incorrectly typed elements prior to the time a dynamically typesafe
* view is generated, and that all subsequent access to the collection takes place through the
* view, it is guaranteed that the collection cannot contain an incorrectly typed
* element.
*
* The generics mechanism in the language provides compile-time (static) type checking, but it
* is possible to defeat this mechanism with unchecked casts. Usually this is not a problem, as
* the compiler issues warnings on all such unchecked operations. There are, however, times when
* static type checking alone is not sufficient. For example, suppose a collection is passed to
* a third-party library and it is imperative that the library code not corrupt the collection
* by inserting an element of the wrong type.
*
* Another use of dynamically typesafe views is debugging. Suppose a program fails with a
* ClassCastException, indicating that an incorrectly typed element was put into a
* parameterized collection. Unfortunately, the exception can occur at any time after the
* erroneous element is inserted, so it typically provides little or no information as to the
* real source of the problem. If the problem is reproducible, one can quickly determine its
* source by temporarily modifying the program to wrap the collection with a dynamically
* typesafe view. For example, this declaration:
*
*
* Collection<String> c = new HashSet<String>();
*
*
* may be replaced temporarily by this one:
*
*
* Collection<String> c = java.util.Collections.checkedCollection(new HashSet<String>(), String.class);
*
*
* Running the program again will cause it to fail at the point where an incorrectly typed
* element is inserted into the collection, clearly identifying the source of the problem. Once
* the problem is fixed, the modified declaration may be reverted back to the original.
*
* The returned collection does not pass the hashCode and equals operations through to
* the backing collection, but relies on Object's equals and hashCode
* methods. This is necessary to preserve the contracts of these operations in the case that the
* backing collection is a set or a list.
*
* The returned collection will be serializable if the specified collection is serializable.
*
* @param c the collection for which a dynamically typesafe view is to be returned
* @param type the type of element that c is permitted to hold
* @return a dynamically typesafe view of the specified collection
*/
public static Collection checkedCollection(Collection c, Class type) {
return java.util.Collections.checkedCollection(c, type);
}
/**
* Returns a dynamically typesafe view of the specified set. Any attempt to insert an element of
* the wrong type will result in an immediate ClassCastException. Assuming a set
* contains no incorrectly typed elements prior to the time a dynamically typesafe view is
* generated, and that all subsequent access to the set takes place through the view, it is
* guaranteed that the set cannot contain an incorrectly typed element.
*
* A discussion of the use of dynamically typesafe views may be found in the documentation for
* the {@link #checkedCollection checkedCollection} method.
*
* The returned set will be serializable if the specified set is serializable.
*
* @param s the set for which a dynamically typesafe view is to be returned
* @param type the type of element that s is permitted to hold
* @return a dynamically typesafe view of the specified set
*/
public static Set checkedSet(Set s, Class type) {
return java.util.Collections.checkedSet(s, type);
}
/**
* Returns a dynamically typesafe view of the specified sorted set. Any attempt to insert an
* element of the wrong type will result in an immediate ClassCastException. Assuming a
* sorted set contains no incorrectly typed elements prior to the time a dynamically typesafe
* view is generated, and that all subsequent access to the sorted set takes place through the
* view, it is guaranteed that the sorted set cannot contain an incorrectly typed
* element.
*
* A discussion of the use of dynamically typesafe views may be found in the documentation for
* the {@link #checkedCollection checkedCollection} method.
*
* The returned sorted set will be serializable if the specified sorted set is serializable.
*
* @param s the sorted set for which a dynamically typesafe view is to be returned
* @param type the type of element that s is permitted to hold
* @return a dynamically typesafe view of the specified sorted set
*/
public static SortedSet checkedSortedSet(SortedSet s, Class type) {
return java.util.Collections.checkedSortedSet(s, type);
}
/**
* Returns a dynamically typesafe view of the specified list. Any attempt to insert an element
* of the wrong type will result in an immediate ClassCastException. Assuming a list
* contains no incorrectly typed elements prior to the time a dynamically typesafe view is
* generated, and that all subsequent access to the list takes place through the view, it is
* guaranteed that the list cannot contain an incorrectly typed element.
*
* A discussion of the use of dynamically typesafe views may be found in the documentation for
* the {@link #checkedCollection checkedCollection} method.
*
* The returned list will be serializable if the specified list is serializable.
*
* @param list the list for which a dynamically typesafe view is to be returned
* @param type the type of element that list is permitted to hold
* @return a dynamically typesafe view of the specified list
*/
public static List checkedList(List list, Class type) {
return java.util.Collections.checkedList(list, type);
}
/**
* Returns a dynamically typesafe view of the specified map. Any attempt to insert a mapping
* whose key or value have the wrong type will result in an immediate
* ClassCastException. Similarly, any attempt to modify the value currently associated
* with a key will result in an immediate ClassCastException, whether the modification
* is attempted directly through the map itself, or through a {@link java.util.Map.Entry} instance
* obtained from the map's {@link Map#entrySet() entry set} view.
*
* Assuming a map contains no incorrectly typed keys or values prior to the time a dynamically
* typesafe view is generated, and that all subsequent access to the map takes place through the
* view (or one of its collection views), it is guaranteed that the map cannot contain an
* incorrectly typed key or value.
*
* A discussion of the use of dynamically typesafe views may be found in the documentation for
* the {@link #checkedCollection checkedCollection} method.
*
* The returned map will be serializable if the specified map is serializable.
*
* @param m the map for which a dynamically typesafe view is to be returned
* @param keyType the type of key that m is permitted to hold
* @param valueType the type of value that m is permitted to hold
* @return a dynamically typesafe view of the specified map
*/
public static Map checkedMap(Map m, Class keyType, Class valueType) {
return java.util.Collections.checkedMap(m, keyType, valueType);
}
/**
* Returns a dynamically typesafe view of the specified sorted map. Any attempt to insert a
* mapping whose key or value have the wrong type will result in an immediate
* ClassCastException. Similarly, any attempt to modify the value currently associated
* with a key will result in an immediate ClassCastException, whether the modification
* is attempted directly through the map itself, or through a {@link java.util.Map.Entry} instance
* obtained from the map's {@link Map#entrySet() entry set} view.
*
* Assuming a map contains no incorrectly typed keys or values prior to the time a dynamically
* typesafe view is generated, and that all subsequent access to the map takes place through the
* view (or one of its collection views), it is guaranteed that the map cannot contain an
* incorrectly typed key or value.
*
* A discussion of the use of dynamically typesafe views may be found in the documentation for
* the {@link #checkedCollection checkedCollection} method.
*
* The returned map will be serializable if the specified map is serializable.
*
* @param m the map for which a dynamically typesafe view is to be returned
* @param keyType the type of key that m is permitted to hold
* @param valueType the type of value that m is permitted to hold
* @return a dynamically typesafe view of the specified map
*/
public static SortedMap checkedSortedMap(SortedMap m, Class keyType,
Class valueType) {
return java.util.Collections.checkedSortedMap(m, keyType, valueType);
}
// Miscellaneous
/**
* The empty set (immutable). This set is serializable.
*
* @see #emptySet()
*/
public static final Set EMPTY_SET = java.util.Collections.EMPTY_SET;
/**
* Returns the empty set (immutable). This set is serializable. Unlike the like-named field,
* this method is parameterized.
*
* This example illustrates the type-safe way to obtain an empty set:
*
*
* Set<String> s = java.util.Collections.emptySet();
*
*
* Implementation note: Implementations of this method need not create a separate Set
* object for each call. Using this method is likely to have comparable cost to using the
* like-named field. (Unlike this method, the field does not provide type safety.)
* @return the empty set
*
* @see #EMPTY_SET
*/
public static final Set emptySet() {
return (Set) EMPTY_SET;
}
/**
* The empty list (immutable). This list is serializable.
*
* @see #emptyList()
*/
public static final List EMPTY_LIST = java.util.Collections.EMPTY_LIST;
/**
* Returns the empty list (immutable). This list is serializable.
*
* This example illustrates the type-safe way to obtain an empty list:
*
*
* List<String> s = java.util.Collections.emptyList();
*
*
* Implementation note: Implementations of this method need not create a separate List
* object for each call. Using this method is likely to have comparable cost to using the
* like-named field. (Unlike this method, the field does not provide type safety.)
*
* @return the empty list
* @see #EMPTY_LIST
*/
public static final List emptyList() {
return (List) EMPTY_LIST;
}
/**
* The empty map (immutable). This map is serializable.
*
* @see #emptyMap()
*/
public static final Map EMPTY_MAP = java.util.Collections.EMPTY_MAP;
/**
* Returns the empty map (immutable). This map is serializable.
*
* This example illustrates the type-safe way to obtain an empty set:
*
*
* Map<String, Date> s = java.util.Collections.emptyMap();
*
*
* Implementation note: Implementations of this method need not create a separate Map
* object for each call. Using this method is likely to have comparable cost to using the
* like-named field. (Unlike this method, the field does not provide type safety.)
* @return the empty map
* @see #EMPTY_MAP
*/
public static final Map emptyMap() {
return (Map) EMPTY_MAP;
}
/**
* Returns an immutable list containing only the specified object. The returned list is
* serializable.
*
* @param o the sole object to be stored in the returned list.
* @return an immutable list containing only the specified object.
*/
public static Set singleton(T o) {
return java.util.Collections.singleton(o);
}
/**
* Returns an immutable list containing only the specified object. The returned list is
* serializable.
*
* @param o the sole object to be stored in the returned list.
* @return an immutable list containing only the specified object.
*/
public static List singletonList(T o) {
return java.util.Collections.singletonList(o);
}
/**
* Returns an immutable map, mapping only the specified key to the specified value. The returned
* map is serializable.
*
* @param key the sole key to be stored in the returned map.
* @param value the value to which the returned map maps key.
* @return an immutable map containing only the specified key-value mapping.
*/
public static Map singletonMap(K key, V value) {
return java.util.Collections.singletonMap(key, value);
}
/**
* Returns an immutable list consisting of n copies of the specified object. The newly
* allocated data object is tiny (it contains a single reference to the data object). This
* method is useful in combination with the List.addAll method to grow lists. The
* returned list is serializable.
*
* @param n the number of elements in the returned list.
* @param o the element to appear repeatedly in the returned list.
* @return an immutable list consisting of n copies of the specified object.
* @throws IllegalArgumentException if n < 0.
* @see List#addAll(Collection)
* @see List#addAll(int, Collection)
*/
public static List nCopies(int n, T o) {
return java.util.Collections.nCopies(n, o);
}
/**
* Returns a comparator that imposes the reverse of the natural ordering on a collection
* of objects that implement the Comparable interface. (The natural ordering is the
* ordering imposed by the objects' own compareTo method.) This enables a simple idiom
* for sorting (or maintaining) collections (or arrays) of objects that implement the
* Comparable interface in reverse-natural-order. For example, suppose a is an array of
* strings. Then:
*
*
* Arrays.sort(a, java.util.Collections.reverseOrder());
*
*
* sorts the array in reverse-lexicographic (alphabetical) order.
*
* The returned comparator is serializable.
*
* @return a comparator that imposes the reverse of the natural ordering on a collection
* of objects that implement the Comparable interface.
* @see Comparable
*/
public static Comparator reverseOrder() {
return java.util.Collections.reverseOrder();
}
/**
* Returns a comparator that imposes the reverse ordering of the specified comparator. If the
* specified comparator is null, this method is equivalent to {@link #reverseOrder()} (in other
* words, it returns a comparator that imposes the reverse of the natural ordering on a
* collection of objects that implement the Comparable interface).
*
* The returned comparator is serializable (assuming the specified comparator is also
* serializable or null).
*
* @param cmp a comparator who's ordering is to be reversed by the returned
* comparator or {@code null}
* @return a comparator that imposes the reverse ordering of the specified comparator.
*/
public static Comparator reverseOrder(Comparator cmp) {
return java.util.Collections.reverseOrder(cmp);
}
/**
* Returns an enumeration over the specified collection. This provides interoperability with
* legacy APIs that require an enumeration as input.
*
* @param c the collection for which an enumeration is to be returned.
* @return an enumeration over the specified collection.
* @see Enumeration
*/
public static Enumeration enumeration(final Collection c) {
return java.util.Collections.enumeration(c);
}
/**
* Returns an array list containing the elements returned by the specified enumeration in the
* order they are returned by the enumeration. This method provides interoperability between
* legacy APIs that return enumerations and new APIs that require collections.
*
* @param e enumeration providing elements for the returned array list
* @return an array list containing the elements returned by the specified enumeration.
* @see Enumeration
* @see ArrayList
*/
public static ArrayList list(Enumeration e) {
return java.util.Collections.list(e);
}
/**
* Returns the number of elements in the specified collection equal to the specified object.
* More formally, returns the number of elements e in the collection such that
* (o == null ? e == null : o.equals(e)).
*
* @param c the collection in which to determine the frequency of o
* @param o the object whose frequency is to be determined
* @return the number of elements in the specified collection equal to the specified object.
* @throws NullPointerException if c is null
*/
public static int frequency(Collection> c, Object o) {
return java.util.Collections.frequency(c, o);
}
/**
* Returns true if the two specified collections have no elements in common.
*
* Care must be exercised if this method is used on collections that do not comply with the
* general contract for Collection. Implementations may elect to iterate over either
* collection and test for containment in the other collection (or to perform any equivalent
* computation). If either collection uses a nonstandard equality test (as does a
* {@link SortedSet} whose ordering is not compatible with equals, or the key set of an
* {@link IdentityHashMap}), both collections must use the same nonstandard equality test, or
* the result of this method is undefined.
*
* Note that it is permissible to pass the same collection in both parameters, in which case the
* method will return true if and only if the collection is empty.
*
* @param c1 a collection
* @param c2 a collection
* @return true if the two specified collections have no elements in common.
* @throws NullPointerException if either collection is null
*/
public static boolean disjoint(Collection> c1, Collection> c2) {
return java.util.Collections.disjoint(c1, c2);
}
/**
* Adds all of the specified elements to the specified collection. Elements to be added may be
* specified individually or as an array. The behavior of this convenience method is identical
* to that of c.addAll(Arrays.asList(elements)), but this method is likely to run
* significantly faster under most implementations.
*
* When elements are specified individually, this method provides a convenient way to add a few
* elements to an existing collection:
*
*
* java.util.Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
*
*
* @param c the collection into which elements are to be inserted
* @param elements the elements to insert into c
* @return true if the collection changed as a result of the call
* @throws UnsupportedOperationException if c does not support the add
* operation
* @throws NullPointerException if elements contains one or more null values and
* c does not permit null elements, or if c or elements
* are null
* @throws IllegalArgumentException if some property of a value in elements prevents it
* from being added to c
* @see Collection#addAll(Collection)
*/
public static boolean addAll(Collection super T> c, T... elements) {
return java.util.Collections.addAll(c, elements);
}
/**
* Returns a set backed by the specified map. The resulting set displays the same ordering,
* concurrency, and performance characteristics as the backing map. In essence, this factory
* method provides a {@link Set} implementation corresponding to any {@link Map} implementation.
* There is no need to use this method on a {@link Map} implementation that already has a
* corresponding {@link Set} implementation (such as {@link HashMap} or {@link TreeMap}).
*
* Each method invocation on the set returned by this method results in exactly one method
* invocation on the backing map or its keySet view, with one exception. The
* addAll method is implemented as a sequence of put invocations on the
* backing map.
*
* The specified map must be empty at the time this method is invoked, and should not be
* accessed directly after this method returns. These conditions are ensured if the map is
* created empty, passed directly to this method, and no reference to the map is retained, as
* illustrated in the following code fragment:
*
*
* Set<Object> weakHashSet = java.util.Collections.newSetFromMap(new WeakHashMap<Object, Boolean>());
*
*
* @param map the backing map
* @return the set backed by the map
* @throws IllegalArgumentException if map is not empty
*/
public static Set newSetFromMap(Map map) {
return java.util.Collections.newSetFromMap(map);
}
/**
* Returns a view of a {@link Deque} as a Last-in-first-out (Lifo) {@link Queue}. Method
* add is mapped to push, remove is mapped to pop and so on.
* This view can be useful when you would like to use a method requiring a Queue but
* you need Lifo ordering.
*
* Each method invocation on the queue returned by this method results in exactly one method
* invocation on the backing deque, with one exception. The {@link Queue#addAll addAll} method
* is implemented as a sequence of {@link Deque#addFirst addFirst} invocations on the backing
* deque.
*
* @param deque the deque
* @return the queue
*/
public static Queue asLifoQueue(Deque deque) {
return java.util.Collections.asLifoQueue(deque);
}
/**
* invert copy map, the key/value pair is inverted.
* @param des destination map
* @param src source map array
* @return the destination map (des)
*/
public static Map invertAddAll(Map des, Map ... src) {
if (src == null || src.length == 0) {
return des;
}
Asserts.notNull(des);
for (Map m : src) {
for (Entry en : (Set)m.entrySet()) {
des.put(en.getValue(), en.getKey());
}
}
return des;
}
/**
* copy source maps to des map
* @param des destination map
* @param src source map array
* @return the destination map (des)
*/
public static Map addAll(Map des, Map ... src) {
if (src == null || src.length == 0) {
return des;
}
Asserts.notNull(des);
for (Map m : src) {
des.putAll(m);
}
return des;
}
/**
* subtract a map which key starts with the prefix, and remove prefix of key
*
* @param map the original map
* @param prefix the key prefix
* @return the subtracted map
*/
public static Map subMap(Map map, String prefix) {
return subMap(map, prefix, true);
}
/**
* subtract a map which key starts with the prefix
*
* @param map the original map
* @param prefix the key prefix
* @param remove remove prefix of key
* @return the subtracted map
*/
public static Map subMap(Map map, String prefix, boolean remove) {
if (isEmpty(map) || Strings.isEmpty(prefix)) {
return map;
}
Map nm = new LinkedHashMap();
int len = prefix.length();
for (Entry en : map.entrySet()) {
String k = en.getKey();
if (k != null && k.startsWith(prefix)) {
if (remove) {
k = k.substring(len);
}
nm.put(k, en.getValue());
}
}
return nm;
}
/**
* remove empty elements from collection
*
* @param coll the collection
* @return the stripped collection (coll)
*/
public static Collection stripToNull(Collection coll) {
if (isEmpty(coll)) {
return null;
}
for (Iterator it = coll.iterator(); it.hasNext();) {
if (Objects.isEmpty(it.next())) {
it.remove();
}
}
return isEmpty(coll) ? null : coll;
}
/**
* remove empty elements from list
*
* @param list the list
* @return the stripped list (list)
*/
public static List stripToNull(List list) {
if (isEmpty(list)) {
return null;
}
for (Iterator it = list.iterator(); it.hasNext();) {
if (Objects.isEmpty(it.next())) {
it.remove();
}
}
return isEmpty(list) ? null : list;
}
/**
* remove empty elements from set
*
* @param set the set
* @return the stripped set (set)
*/
public static Set stripToNull(Set set) {
if (isEmpty(set)) {
return null;
}
for (Iterator it = set.iterator(); it.hasNext();) {
if (Objects.isEmpty(it.next())) {
it.remove();
}
}
return isEmpty(set) ? null : set;
}
/**
* remove empty elements from collection
*
* @param coll the collection
* @return the stripped collection (coll)
*/
public static Collection stripToEmpty(Collection coll) {
if (coll == null) {
return new ArrayList();
}
for (Iterator it = coll.iterator(); it.hasNext();) {
if (Objects.isEmpty(it.next())) {
it.remove();
}
}
return coll;
}
/**
* remove empty elements from list
*
* @param list the list
* @return the stripped list (list)
*/
public static List stripToEmpty(List list) {
if (list == null) {
return new ArrayList();
}
for (Iterator it = list.iterator(); it.hasNext();) {
if (Objects.isEmpty(it.next())) {
it.remove();
}
}
return list;
}
/**
* remove empty elements from set
*
* @param set the set
* @return the stripped set (set)
*/
public static Set stripToEmpty(Set set) {
if (set == null) {
return new HashSet();
}
for (Iterator it = set.iterator(); it.hasNext();) {
if (Objects.isEmpty(it.next())) {
it.remove();
}
}
return set;
}
/**
* @param col collection
* @return true if all items is empty
*/
public static boolean isItemsEmpty(Collection> col) {
if (isEmpty(col)) {
return true;
}
for (Object o : col) {
if (Objects.isNotEmpty(o)) {
return false;
}
}
return true;
}
//--------------------------------------------------------------------------
private static class ListSet implements Set {
private final List list;
/**
* @param list the list
*/
public ListSet(List list) {
this.list = list;
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection extends E> c) {
return list.addAll(c);
}
@Override
public boolean retainAll(Collection> c) {
return list.retainAll(c);
}
@Override
public boolean removeAll(Collection> c) {
return list.removeAll(c);
}
@Override
public void clear() {
list.clear();
}
}
/**
* Returns a set backed by the specified list. (Changes to the returned list
* "write through" to the list.)
*
* This method also provides a convenient way to convert list to set
*
* @param list the list by which the set will be backed
* @return a set of the specified list
*/
public static Set asSet(List list) {
if (list == null) {
return null;
}
return new ListSet(list);
}
}