blob: 1d674f5d1011056d639d79509880327f26577bbb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.collection.PredicatedCollection;
import org.apache.commons.collections.collection.SynchronizedCollection;
import org.apache.commons.collections.collection.TransformedCollection;
import org.apache.commons.collections.collection.UnmodifiableBoundedCollection;
import org.apache.commons.collections.collection.UnmodifiableCollection;
/**
* Provides utility methods and decorators for {@link Collection} instances.
* Method parameters will take {@link Iterable} objects when possible.
*
* @since Commons Collections 1.0
* @version $Revision$ $Date$
*
* @author Rodney Waldhoff
* @author Paul Jack
* @author Stephen Colebourne
* @author Steve Downey
* @author Herve Quiroz
* @author Peter KoBek
* @author Matthew Hawthorne
* @author Janek Bogucki
* @author Phil Steitz
* @author Steven Melzer
* @author Jon Schewe
* @author Neil O'Toole
* @author Stephen Smith
* @author Stephen Kestle
*/
//TODO - note generic types for review in wiki - especially <?> ones
//TODO - doc Cardinality Helpers
public class CollectionUtils {
private static class CardinalityHelper<O> {
final Map<O, Integer> cardinalityA, cardinalityB;
public CardinalityHelper(Iterable<? extends O> a, Iterable<? extends O> b) {
cardinalityA = CollectionUtils.<O>getCardinalityMap(a);
cardinalityB = CollectionUtils.<O>getCardinalityMap(b);
}
public final int max(Object obj) {
return Math.max(freqA(obj), freqB(obj));
}
public final int min(Object obj) {
return Math.min(freqA(obj), freqB(obj));
}
public int freqA(Object obj) {
return getFreq(obj, cardinalityA);
}
public int freqB(Object obj) {
return getFreq(obj, cardinalityB);
}
private final int getFreq(final Object obj, final Map<?, Integer> freqMap) {
Integer count = freqMap.get(obj);
if (count != null) {
return count;
}
return 0;
}
}
private static class SetOperationCardinalityHelper<O> extends CardinalityHelper<O> implements Iterable<O> {
private final Set<O> elements;
private final List<O> newList;
public SetOperationCardinalityHelper(Iterable<? extends O> a, Iterable<? extends O> b) {
super(a, b);
elements = new HashSet<O>();
addAll(elements, a);
addAll(elements, b);
newList = new ArrayList<O>();
}
public Iterator<O> iterator() {
return elements.iterator();
}
public void setCardinality(O obj, int count) {
for (int i = 0; i < count; i++) {
newList.add(obj);
}
}
public Collection<O> list() {
return newList;
}
}
/**
* An empty unmodifiable collection.
* The JDK provides empty Set and List implementations which could be used for
* this purpose. However they could be cast to Set or List which might be
* undesirable. This implementation only implements Collection.
*/
@SuppressWarnings("unchecked")
public static final Collection EMPTY_COLLECTION = UnmodifiableCollection.decorate(new ArrayList<Object>());
/**
* <code>CollectionUtils</code> should not normally be instantiated.
*/
public CollectionUtils() {
}
/**
* Returns the immutable EMPTY_COLLECTION with generic type safety.
*
* @see #EMPTY_COLLECTION
* @since 4.0
* @return immutable empty collection
*/
@SuppressWarnings("unchecked")
public static <T> Collection<T> emptyCollection() {
return EMPTY_COLLECTION;
}
/**
* Returns a {@link Collection} containing the union of the given
* {@link Collection}s.
* <p>
* 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
* @param <O> the generic type that is able to represent the types contained
* in both input collections.
* @return the union of the two collections
* @see Collection#addAll
*/
public static <O> Collection<O> union(final Iterable<? extends O> a, final Iterable<? extends O> b) {
SetOperationCardinalityHelper<O> helper = new SetOperationCardinalityHelper<O>(a, b);
for (O obj : helper) {
helper.setCardinality(obj, helper.max(obj));
}
return helper.list();
}
/**
* Returns a {@link Collection} containing the intersection of the given
* {@link Collection}s.
* <p>
* 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
* @param <O> the generic type that is able to represent the types contained
* in both input collections.
* @return the intersection of the two collections
* @see Collection#retainAll
* @see #containsAny
*/
public static <O> Collection<O> intersection(final Iterable<? extends O> a, final Iterable<? extends O> b) {
SetOperationCardinalityHelper<O> helper = new SetOperationCardinalityHelper<O>(a, b);
for (O obj : helper) {
helper.setCardinality(obj, helper.min(obj));
}
return helper.list();
}
/**
* Returns a {@link Collection} containing the exclusive disjunction
* (symmetric difference) of the given {@link Collection}s.
* <p>
* The cardinality of each element <i>e</i> in the returned
* {@link Collection} will be equal to
* <tt>max(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>)) - min(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>))</tt>.
* <p>
* This is equivalent to
* <tt>{@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})</tt>
* or
* <tt>{@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)})</tt>.
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @param <O> the generic type that is able to represent the types contained
* in both input collections.
* @return the symmetric difference of the two collections
*/
public static <O> Collection<O> disjunction(final Iterable<? extends O> a, final Iterable<? extends O> b) {
SetOperationCardinalityHelper<O> helper = new SetOperationCardinalityHelper<O>(a, b);
for (O obj : helper) {
helper.setCardinality(obj, helper.max(obj) - helper.min(obj));
}
return helper.list();
}
/**
* Returns a new {@link Collection} containing <tt><i>a</i> - <i>b</i></tt>.
* The cardinality of each element <i>e</i> in the returned {@link Collection}
* will be the cardinality of <i>e</i> in <i>a</i> minus the cardinality
* of <i>e</i> in <i>b</i>, 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
* @param <O> the generic type that is able to represent the types contained
* in both input collections.
* @return a new collection with the results
* @see Collection#removeAll
*/
public static <O> Collection<O> subtract(final Iterable<? extends O> a, final Iterable<? extends O> b) {
ArrayList<O> list = new ArrayList<O>();
addAll(list, a);
for (O element : b) {
list.remove(element);
}
return list;
}
/**
* Returns <code>true</code> iff at least one element is in both collections.
* <p>
* In other words, this method returns <code>true</code> iff the
* {@link #intersection} of <i>coll1</i> and <i>coll2</i> is not empty.
*
* @param coll1 the first collection, must not be null
* @param coll2 the first collection, must not be null
* @return <code>true</code> iff the intersection of the collections is non-empty
* @since 2.1
* @see #intersection
*/
public static boolean containsAny(final Collection<?> coll1, final Collection<?> coll2) {
if (coll1.size() < coll2.size()) {
for (Object aColl1 : coll1) {
if (coll2.contains(aColl1)) {
return true;
}
}
} else {
for (Object aColl2 : coll2) {
if (coll1.contains(aColl2)) {
return true;
}
}
}
return false;
}
/**
* 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}.
* <p>
* 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
* @param <O>
* the type of object in the returned {@link Map}. This is a
* super type of <I>.
* @return the populated cardinality map
*/
public static <O> Map<O, Integer> getCardinalityMap(final Iterable<? extends O> coll) {
Map<O, Integer> count = new HashMap<O, Integer>();
for (O obj : coll) {
Integer c = count.get(obj);
if (c == null) {
count.put(obj, 1);
} else {
count.put(obj, c + 1);
}
}
return count;
}
/**
* Returns <tt>true</tt> iff <i>a</i> is a sub-collection of <i>b</i>,
* that is, iff the cardinality of <i>e</i> in <i>a</i> is less than or
* equal to the cardinality of <i>e</i> in <i>b</i>, for each element <i>e</i>
* in <i>a</i>.
*
* @param a the first (sub?) collection, must not be null
* @param b the second (super?) collection, must not be null
* @return <code>true</code> iff <i>a</i> is a sub-collection of <i>b</i>
* @see #isProperSubCollection
* @see Collection#containsAll
*/
public static boolean isSubCollection(final Collection<?> a, final Collection<?> b) {
CardinalityHelper<Object> helper = new CardinalityHelper<Object>(a, b);
for (Object obj : a) {
if (helper.freqA(obj) > helper.freqB(obj)) {
return false;
}
}
return true;
}
/**
* Returns <tt>true</tt> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>,
* that is, iff the cardinality of <i>e</i> in <i>a</i> is less
* than or equal to the cardinality of <i>e</i> in <i>b</i>,
* for each element <i>e</i> in <i>a</i>, and there is at least one
* element <i>f</i> such that the cardinality of <i>f</i> in <i>b</i>
* is strictly greater than the cardinality of <i>f</i> in <i>a</i>.
* <p>
* The implementation assumes
* <ul>
* <li><code>a.size()</code> and <code>b.size()</code> represent the
* total cardinality of <i>a</i> and <i>b</i>, resp. </li>
* <li><code>a.size() < Integer.MAXVALUE</code></li>
* </ul>
*
* @param a the first (sub?) collection, must not be null
* @param b the second (super?) collection, must not be null
* @return <code>true</code> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>
* @see #isSubCollection
* @see Collection#containsAll
*/
public static boolean isProperSubCollection(final Collection<?> a, final Collection<?> b) {
return (a.size() < b.size()) && CollectionUtils.isSubCollection(a, b);
}
/**
* Returns <tt>true</tt> iff the given {@link Collection}s contain
* exactly the same elements with exactly the same cardinalities.
* <p>
* That is, iff the cardinality of <i>e</i> in <i>a</i> is
* equal to the cardinality of <i>e</i> in <i>b</i>,
* for each element <i>e</i> in <i>a</i> or <i>b</i>.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return <code>true</code> 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;
}
final CardinalityHelper<Object> helper = new CardinalityHelper<Object>(a, b);
if(helper.cardinalityA.size() != helper.cardinalityB.size()) {
return false;
}
for( Object obj : helper.cardinalityA.keySet()) {
if(helper.freqA(obj) != helper.freqB(obj)) {
return false;
}
}
return true;
}
/**
* Returns the number of occurrences of <i>obj</i> in <i>coll</i>.
*
* @param obj the object to find the cardinality of
* @param coll the {@link Iterable} to search
* @param <O> the type of object that the {@link Iterable} may contain.
* @return the the number of occurrences of obj in coll
*/
public static <O> int cardinality(O obj, final Iterable<? super O> coll) {
if (coll instanceof Set<?>) {
return (((Set<? super O>) coll).contains(obj) ? 1 : 0);
}
if (coll instanceof Bag<?>) {
return ((Bag<? super O>) coll).getCount(obj);
}
int count = 0;
if (obj == null) {
for (Object element : coll) {
if (element == null) {
count++;
}
}
} else {
for (Object element : coll) {
if (obj.equals(element)) {
count++;
}
}
}
return count;
}
/**
* Finds the first element in the given collection which matches the given predicate.
* <p>
* If the input collection or predicate is null, or no element of the collection
* matches the predicate, null is returned.
*
* @param collection the collection to search, may be null
* @param predicate the predicate to use, may be null
* @return the first element of the collection which matches the predicate or null if none could be found
*/
public static <T> T find(Collection<T> collection, Predicate<? super T> predicate) {
if (collection != null && predicate != null) {
for (T item : collection) {
if (predicate.evaluate(item)) {
return item;
}
}
}
return null;
}
/**
* Executes the given closure on each element in the collection.
* <p>
* If the input collection or closure is null, there is no change made.
*
* @param collection
* the collection to get the input from, may be null
* @param closure
* the closure to perform, may be null
* @return closure
*/
public static <T, C extends Closure<? super T>> C forAllDo(Collection<T> collection, C closure) {
if (collection != null && closure != null) {
for (T element : collection) {
closure.execute(element);
}
}
return closure;
}
/**
* Filter the collection by applying a Predicate to each element. If the
* predicate returns false, remove the element.
* <p>
* If the input collection or predicate is null, there is no change made.
*
* @param collection
* the collection to get the input from, may be null
* @param predicate
* the predicate to use as a filter, may be null
*/
public static <T> void filter(Iterable<T> collection, Predicate<? super T> predicate) {
if (collection != null && predicate != null) {
for (Iterator<T> it = collection.iterator(); it.hasNext();) {
if (!predicate.evaluate(it.next())) {
it.remove();
}
}
}
}
/**
* Transform the collection by applying a Transformer to each element.
* <p>
* If the input collection or transformer is null, there is no change made.
* <p>
* This routine is best for Lists, for which set() is used to do the
* transformations "in place." For other Collections, clear() and addAll()
* are used to replace elements.
* <p>
* If the input collection controls its input, such as a Set, and the
* Transformer creates duplicates (or are otherwise invalid), the collection
* may reduce in size due to calling this method.
*
* @param collection
* the {@link Iterable} to get the input from, may be null
* @param transformer
* the transformer to perform, may be null
*/
public static <C> void transform(Collection<C> collection,
Transformer<? super C, ? extends C> transformer) {
if (collection != null && transformer != null) {
if (collection instanceof List<?>) {
List<C> list = (List<C>) collection;
for (ListIterator<C> it = list.listIterator(); it.hasNext();) {
it.set(transformer.transform(it.next()));
}
} else {
Collection<C> resultCollection = collect(collection, transformer);
collection.clear();
collection.addAll(resultCollection);
}
}
}
/**
* Counts the number of elements in the input collection that match the
* predicate.
* <p>
* A <code>null</code> collection or predicate matches no elements.
*
* @param input
* the {@link Iterable} to get the input from, may be null
* @param predicate
* the predicate to use, may be null
* @return the number of matches for the predicate in the collection
*/
public static <C> int countMatches(Iterable<C> input, Predicate<? super C> predicate) {
int count = 0;
if (input != null && predicate != null) {
for (C o : input) {
if (predicate.evaluate(o)) {
count++;
}
}
}
return count;
}
/**
* Answers true if a predicate is true for at least one element of a
* collection.
* <p>
* A <code>null</code> collection or predicate returns false.
*
* @param input
* the {@link Iterable} to get the input from, may be null
* @param predicate
* the predicate to use, may be null
* @return true if at least one element of the collection matches the
* predicate
*/
public static <C> boolean exists(Iterable<C> input, Predicate<? super C> predicate) {
if (input != null && predicate != null) {
for (C o : input) {
if (predicate.evaluate(o)) {
return true;
}
}
}
return false;
}
/**
* Selects all elements from input collection which match the given
* predicate into an output collection.
* <p>
* A <code>null</code> predicate matches no elements.
*
* @param inputCollection
* the collection to get the input from, may not be null
* @param predicate
* the predicate to use, may be null
* @return the elements matching the predicate (new list)
* @throws NullPointerException
* if the input collection is null
*/
public static <O> Collection<O> select(Collection<? extends O> inputCollection,
Predicate<? super O> predicate) {
return select(inputCollection, predicate, new ArrayList<O>(inputCollection.size()));
}
/**
* Selects all elements from input collection which match the given
* predicate and adds them to outputCollection.
* <p>
* If the input collection or predicate is null, there is no change to the
* output collection.
*
* @param inputCollection
* the collection to get the input from, may be null
* @param predicate
* the predicate to use, may be null
* @param outputCollection
* the collection to output into, may not be null
* @return outputCollection
*/
public static <O, R extends Collection<? super O>> R select(Collection<? extends O> inputCollection,
Predicate<? super O> predicate, R outputCollection) {
if (inputCollection != null && predicate != null) {
for (O item : inputCollection) {
if (predicate.evaluate(item)) {
outputCollection.add(item);
}
}
}
return outputCollection;
}
/**
* Selects all elements from inputCollection which don't match the given
* predicate into an output collection.
* <p>
* If the input predicate is <code>null</code>, the result is an empty
* list.
*
* @param inputCollection
* the collection to get the input from, may not be null
* @param predicate
* the predicate to use, may be null
* @return the elements <b>not</b> matching the predicate (new list)
* @throws NullPointerException
* if the input collection is null
*/
public static <O> Collection<O> selectRejected(Collection<? extends O> inputCollection,
Predicate<? super O> predicate) {
return selectRejected(inputCollection, predicate, new ArrayList<O>(inputCollection.size()));
}
/**
* Selects all elements from inputCollection which don't match the given
* predicate and adds them to outputCollection.
* <p>
* If the input predicate is <code>null</code>, no elements are added to
* <code>outputCollection</code>.
*
* @param inputCollection
* the collection to get the input from, may be null
* @param predicate
* the predicate to use, may be null
* @param outputCollection
* the collection to output into, may not be null
* @return outputCollection
*/
public static <O, R extends Collection<? super O>> R selectRejected(
Collection<? extends O> inputCollection, Predicate<? super O> predicate, R outputCollection) {
if (inputCollection != null && predicate != null) {
for (O item : inputCollection) {
if (!predicate.evaluate(item)) {
outputCollection.add(item);
}
}
}
return outputCollection;
}
/**
* Returns a new Collection consisting of the elements of inputCollection
* transformed by the given transformer.
* <p>
* If the input transformer is null, the result is an empty list.
*
* @param inputCollection
* the collection to get the input from, may not be null
* @param transformer
* the transformer to use, may be null
* @param <I> the type of object in the input collection
* @param <O> the type of object in the output collection
* @return the transformed result (new list)
* @throws NullPointerException
* if the input collection is null
*/
public static <I, O> Collection<O> collect(Iterable<I> inputCollection,
Transformer<? super I, ? extends O> transformer) {
ArrayList<O> answer = new ArrayList<O>();
collect(inputCollection, transformer, answer);
return answer;
}
/**
* Transforms all elements from the inputIterator with the given transformer
* and adds them to the outputCollection.
* <p>
* If the input iterator or transformer is null, the result is an empty
* list.
*
* @param inputIterator
* the iterator to get the input from, may be null
* @param transformer
* the transformer to use, may be null
* @param <I> the type of object in the input collection
* @param <O> the type of object in the output collection
* @return the transformed result (new list)
*/
public static <I, O> Collection<O> collect(Iterator<I> inputIterator,
Transformer<? super I, ? extends O> transformer) {
ArrayList<O> answer = new ArrayList<O>();
collect(inputIterator, transformer, answer);
return answer;
}
/**
* Transforms all elements from inputCollection with the given transformer
* and adds them to the outputCollection.
* <p>
* If the input collection or transformer is null, there is no change to the
* output collection.
*
* @param inputCollection the collection to get the input from, may be null
* @param transformer the transformer to use, may be null
* @param outputCollection the collection to output into, may not be null
* @param <I> the type of object in the input collection
* @param <O> the type of object in the output collection
* @param <R> the output type of the transformer - this extends O.
* @return the outputCollection with the transformed input added
* @throws NullPointerException if the output collection is null
*/
public static <I, O, R extends Collection<? super O>> R collect(Iterable<? extends I> inputCollection,
final Transformer<? super I, ? extends O> transformer, final R outputCollection) {
if (inputCollection != null) {
return collect(inputCollection.iterator(), transformer, outputCollection);
}
return outputCollection;
}
/**
* Transforms all elements from the inputIterator with the given transformer
* and adds them to the outputCollection.
* <p>
* If the input iterator or transformer is null, there is no change to the
* output collection.
*
* @param inputIterator the iterator to get the input from, may be null
* @param transformer the transformer to use, may be null
* @param outputCollection the collection to output into, may not be null
* @param <I> the type of object in the input collection
* @param <O> the type of object in the output collection
* @param <R> the output type of the transformer - this extends O.
* @return the outputCollection with the transformed input added
* @throws NullPointerException if the output collection is null
*/
//TODO - deprecate and replace with IteratorIterable
public static <I, O, R extends Collection<? super O>> R collect(Iterator<? extends I> inputIterator,
final Transformer<? super I, ? extends O> transformer, final R outputCollection) {
if (inputIterator != null && transformer != null) {
while (inputIterator.hasNext()) {
I item = inputIterator.next();
O value = transformer.transform(item);
outputCollection.add(value);
}
}
return outputCollection;
}
//-----------------------------------------------------------------------
/**
* 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
* @since Commons Collections 3.2
*/
public static <T> boolean addIgnoreNull(Collection<T> collection, T object) {
return (object == null ? false : collection.add(object));
}
/**
* Adds all elements in the {@link Iterable} to the given collection. If the
* {@link Iterable} is a {@link Collection} then it is cast and will be
* added using {@link Collection#addAll(Collection)} instead of iterating.
*
* @param collection
* the collection to add to, must not be null
* @param iterable
* the iterable of elements to add, must not be null
* @return a boolean indicating whether the collection has changed or not.
* @throws NullPointerException
* if the collection or iterator is null
*/
public static <C> boolean addAll(Collection<C> collection, Iterable<? extends C> iterable) {
if (iterable instanceof Collection<?>) {
return collection.addAll((Collection<? extends C>) iterable);
}
return addAll(collection, iterable.iterator());
}
/**
* 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
* @return a boolean indicating whether the collection has changed or not.
* @throws NullPointerException
* if the collection or iterator is null
*/
public static <C> boolean addAll(Collection<C> collection, Iterator<? extends C> iterator) {
boolean changed = false;
while (iterator.hasNext()) {
changed |= collection.add(iterator.next());
}
return changed;
}
/**
* 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
*/
//TODO return boolean or collection - check other add() methods too.
public static <C> void addAll(Collection<C> collection, Enumeration<? extends C> enumeration) {
while (enumeration.hasMoreElements()) {
collection.add(enumeration.nextElement());
}
}
/**
* Adds all elements in the array to the given collection.
*
* @param collection
* the collection to add to, must not be null
* @param elements
* the array of elements to add, must not be null
* @throws NullPointerException
* if the collection or array is null
*/
public static <C> void addAll(Collection<C> collection, C[] elements) {
for (int i = 0, size = elements.length; i < size; i++) {
collection.add(elements[i]);
}
}
/**
* Returns the <code>index</code>-th value in {@link Iterator}, throwing
* <code>IndexOutOfBoundsException</code> if there is no such element.
* The Iterator is advanced to
* <code>index</code> (or to the end, if <code>index</code> exceeds the
* number of entries) as a side effect of this method.</li>
*
* @param iterator the iterator to get a value from
* @param index the index to get
* @param <T> the type of object in the {@link Iterator}
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
* @throws IllegalArgumentException if the object type is invalid
*/
public static <T> T get(Iterator<T> iterator, int index) {
int i = index;
checkIndexBounds(i);
while (iterator.hasNext()) {
i--;
if (i == -1) {
return iterator.next();
}
iterator.next();
}
throw new IndexOutOfBoundsException("Entry does not exist: " + i);
}
/**
* Ensures an index is not negative.
* @param index the index to check.
* @throws IndexOutOfBoundsException if the index is negative.
*/
private static void checkIndexBounds(int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("Index cannot be negative: " + index);
}
}
/**
* Returns the <code>index</code>-th value in the <code>iterable</code>'s {@link Iterator}, throwing
* <code>IndexOutOfBoundsException</code> if there is no such element.
* <p>
* If the {@link Iterable} is a {@link List}, then it will use {@link List#get(int)}.
*
* @param iterable the {@link Iterable} to get a value from
* @param index the index to get
* @param <T> the type of object in the {@link Iterable}.
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
*/
public static <T> T get(Iterable<T> iterable, int index) {
checkIndexBounds(index);
if (iterable instanceof List<?>) {
return ((List<T>) iterable).get(index);
}
return get(iterable.iterator(), index);
}
/**
* Returns the <code>index</code>-th value in <code>object</code>, throwing
* <code>IndexOutOfBoundsException</code> if there is no such element or
* <code>IllegalArgumentException</code> if <code>object</code> is not an
* instance of one of the supported types.
* <p>
* The supported types, and associated semantics are:
* <ul>
* <li> Map -- the value returned is the <code>Map.Entry</code> in position
* <code>index</code> in the map's <code>entrySet</code> iterator,
* if there is such an entry.</li>
* <li> List -- this method is equivalent to the list's get method.</li>
* <li> Array -- the <code>index</code>-th array entry is returned,
* if there is such an entry; otherwise an <code>IndexOutOfBoundsException</code>
* is thrown.</li>
* <li> Collection -- the value returned is the <code>index</code>-th object
* returned by the collection's default iterator, if there is such an element.</li>
* <li> Iterator or Enumeration -- the value returned is the
* <code>index</code>-th object in the Iterator/Enumeration, if there
* is such an element. The Iterator/Enumeration is advanced to
* <code>index</code> (or to the end, if <code>index</code> exceeds the
* number of entries) as a side effect of this method.</li>
* </ul>
*
* @param object the object to get a value from
* @param index the index to get
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
* @throws IllegalArgumentException if the object type is invalid
*/
public static Object get(Object object, int index) {
int i = index;
if (i < 0) {
throw new IndexOutOfBoundsException("Index cannot be negative: " + i);
}
if (object instanceof Map<?,?>) {
Map<?, ?> map = (Map<?, ?>) object;
Iterator<?> iterator = map.entrySet().iterator();
return get(iterator, i);
} else if (object instanceof Object[]) {
return ((Object[]) object)[i];
} else if (object instanceof Iterator<?>) {
Iterator<?> it = (Iterator<?>) object;
while (it.hasNext()) {
i--;
if (i == -1) {
return it.next();
}
it.next();
}
throw new IndexOutOfBoundsException("Entry does not exist: " + i);
} else if (object instanceof Collection<?>) {
Iterator<?> iterator = ((Collection<?>) object).iterator();
return get(iterator, i);
} else if (object instanceof Enumeration<?>) {
Enumeration<?> it = (Enumeration<?>) object;
while (it.hasMoreElements()) {
i--;
if (i == -1) {
return it.nextElement();
} else {
it.nextElement();
}
}
throw new IndexOutOfBoundsException("Entry does not exist: " + i);
} else if (object == null) {
throw new IllegalArgumentException("Unsupported object type: null");
} else {
try {
return Array.get(object, i);
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
}
/**
* Returns the <code>index</code>-th <code>Map.Entry</code> in the <code>map</code>'s <code>entrySet</code>, throwing
* <code>IndexOutOfBoundsException</code> if there is no such element.
*
* @param map the object to get a value from
* @param index the index to get
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
*/
public static <K,V> Map.Entry<K, V> get(Map<K,V> map, int index) {
checkIndexBounds(index);
return get(map.entrySet(), index);
}
/**
* Gets the size of the collection/iterator specified.
* <p>
* This method can handles objects as follows
* <ul>
* <li>Collection - the collection size
* <li>Map - the map size
* <li>Array - the array size
* <li>Iterator - the number of elements remaining in the iterator
* <li>Enumeration - the number of elements remaining in the enumeration
* </ul>
*
* @param object the object to get the size of
* @return the size of the specified collection
* @throws IllegalArgumentException thrown if object is not recognised or null
* @since Commons Collections 3.1
*/
public static int size(Object object) {
int total = 0;
if (object instanceof Map<?,?>) {
total = ((Map<?, ?>) object).size();
} else if (object instanceof Collection<?>) {
total = ((Collection<?>) object).size();
} else if (object instanceof Object[]) {
total = ((Object[]) object).length;
} else if (object instanceof Iterator<?>) {
Iterator<?> it = (Iterator<?>) object;
while (it.hasNext()) {
total++;
it.next();
}
} else if (object instanceof Enumeration<?>) {
Enumeration<?> it = (Enumeration<?>) object;
while (it.hasMoreElements()) {
total++;
it.nextElement();
}
} else if (object == null) {
throw new IllegalArgumentException("Unsupported object type: null");
} else {
try {
total = Array.getLength(object);
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
return total;
}
/**
* Checks if the specified collection/array/iterator is empty.
* <p>
* This method can handles objects as follows
* <ul>
* <li>Collection - via collection isEmpty
* <li>Map - via map isEmpty
* <li>Array - using array size
* <li>Iterator - via hasNext
* <li>Enumeration - via hasMoreElements
* </ul>
* <p>
* Note: This method is named to avoid clashing with
* {@link #isEmpty(Collection)}.
*
* @param object the object to get the size of, not null
* @return true if empty
* @throws IllegalArgumentException thrown if object is not recognised or null
* @since Commons Collections 3.2
*/
public static boolean sizeIsEmpty(Object object) {
if (object instanceof Collection<?>) {
return ((Collection<?>) object).isEmpty();
} else if (object instanceof Map<?, ?>) {
return ((Map<?, ?>) object).isEmpty();
} else if (object instanceof Object[]) {
return ((Object[]) object).length == 0;
} else if (object instanceof Iterator<?>) {
return ((Iterator<?>) object).hasNext() == false;
} else if (object instanceof Enumeration<?>) {
return ((Enumeration<?>) object).hasMoreElements() == false;
} else if (object == null) {
throw new IllegalArgumentException("Unsupported object type: null");
} else {
try {
return Array.getLength(object) == 0;
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
}
//-----------------------------------------------------------------------
/**
* Null-safe check if the specified collection is empty.
* <p>
* Null returns true.
*
* @param coll the collection to check, may be null
* @return true if empty or null
* @since Commons Collections 3.2
*/
public static boolean isEmpty(Collection<?> coll) {
return (coll == null || coll.isEmpty());
}
/**
* Null-safe check if the specified collection is not empty.
* <p>
* Null returns false.
*
* @param coll the collection to check, may be null
* @return true if non-null and non-empty
* @since Commons Collections 3.2
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}
//-----------------------------------------------------------------------
/**
* Reverses the order of the given array.
*
* @param array the array to reverse
*/
public static void reverseArray(Object[] array) {
int i = 0;
int j = array.length - 1;
Object tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Returns true if no more elements can be added to the Collection.
* <p>
* This method uses the {@link BoundedCollection} interface to determine the
* full status. If the collection does not implement this interface then
* false is returned.
* <p>
* The collection does not have to implement this interface directly.
* If the collection has been decorated using the decorators subpackage
* then these will be removed to access the BoundedCollection.
*
* @param coll the collection to check
* @return true if the BoundedCollection is full
* @throws NullPointerException if the collection is null
*/
@SuppressWarnings("unchecked")
public static boolean isFull(Collection<?> coll) {
if (coll == null) {
throw new NullPointerException("The collection must not be null");
}
if (coll instanceof BoundedCollection) {
return ((BoundedCollection<?>) coll).isFull();
}
try {
BoundedCollection<?> bcoll = UnmodifiableBoundedCollection.decorateUsing((Collection<Object>) coll);
return bcoll.isFull();
} catch (IllegalArgumentException ex) {
return false;
}
}
/**
* Get the maximum number of elements that the Collection can contain.
* <p>
* This method uses the {@link BoundedCollection} interface to determine the
* maximum size. If the collection does not implement this interface then
* -1 is returned.
* <p>
* The collection does not have to implement this interface directly.
* If the collection has been decorated using the decorators subpackage
* then these will be removed to access the BoundedCollection.
*
* @param coll the collection to check
* @return the maximum size of the BoundedCollection, -1 if no maximum size
* @throws NullPointerException if the collection is null
*/
@SuppressWarnings("unchecked")
public static int maxSize(Collection<?> coll) {
if (coll == null) {
throw new NullPointerException("The collection must not be null");
}
if (coll instanceof BoundedCollection) {
return ((BoundedCollection<?>) coll).maxSize();
}
try {
BoundedCollection<?> bcoll = UnmodifiableBoundedCollection.decorateUsing((Collection<Object>) coll);
return bcoll.maxSize();
} catch (IllegalArgumentException ex) {
return -1;
}
}
//-----------------------------------------------------------------------
/**
* Returns a collection containing all the elements in <code>collection</code>
* that are also in <code>retain</code>. The cardinality of an element <code>e</code>
* in the returned collection is the same as the cardinality of <code>e</code>
* in <code>collection</code> unless <code>retain</code> does not contain <code>e</code>, in which
* case the cardinality is zero. This method is useful if you do not wish to modify
* the collection <code>c</code> and thus cannot call <code>c.retainAll(retain);</code>.
*
* @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 <code>Collection</code> containing all the elements of <code>collection</code>
* that occur at least once in <code>retain</code>.
* @throws NullPointerException if either parameter is null
* @since Commons Collections 3.2
*/
public static <C> Collection<C> retainAll(Collection<C> collection, Collection<?> retain) {
return ListUtils.retainAll(collection, retain);
}
/**
* Removes the elements in <code>remove</code> from <code>collection</code>. That is, this
* method returns a collection containing all the elements in <code>c</code>
* that are not in <code>remove</code>. The cardinality of an element <code>e</code>
* in the returned collection is the same as the cardinality of <code>e</code>
* in <code>collection</code> unless <code>remove</code> contains <code>e</code>, in which
* case the cardinality is zero. This method is useful if you do not wish to modify
* the collection <code>c</code> and thus cannot call <code>collection.removeAll(remove);</code>.
*
* @param collection the collection from which items are removed (in the returned collection)
* @param remove the items to be removed from the returned <code>collection</code>
* @return a <code>Collection</code> containing all the elements of <code>collection</code> except
* any elements that also occur in <code>remove</code>.
* @throws NullPointerException if either parameter is null
* @since Commons Collections 3.3 (method existed in 3.2 but was completely broken)
*/
public static <E> Collection<E> removeAll(Collection<E> collection, Collection<?> remove) {
return ListUtils.removeAll(collection, remove);
}
//-----------------------------------------------------------------------
/**
* Returns a synchronized collection backed by the given collection.
* <p>
* You must manually synchronize on the returned buffer's iterator to
* avoid non-deterministic behavior:
*
* <pre>
* Collection c = CollectionUtils.synchronizedCollection(myCollection);
* synchronized (c) {
* Iterator i = c.iterator();
* while (i.hasNext()) {
* process (i.next());
* }
* }
* </pre>
*
* This method uses the implementation in the decorators subpackage.
*
* @param collection the collection to synchronize, must not be null
* @return a synchronized collection backed by the given collection
* @throws IllegalArgumentException if the collection is null
*/
public static <C> Collection<C> synchronizedCollection(Collection<C> collection) {
return SynchronizedCollection.decorate(collection);
}
/**
* Returns an unmodifiable collection backed by the given collection.
* <p>
* This method uses the implementation in the decorators subpackage.
*
* @param collection the collection to make unmodifiable, must not be null
* @return an unmodifiable collection backed by the given collection
* @throws IllegalArgumentException if the collection is null
*/
public static <C> Collection<C> unmodifiableCollection(Collection<C> collection) {
return UnmodifiableCollection.decorate(collection);
}
/**
* Returns a predicated (validating) collection backed by the given collection.
* <p>
* Only objects that pass the test in the given predicate can be added to the collection.
* Trying to add an invalid object results in an IllegalArgumentException.
* It is important not to use the original collection after invoking this method,
* as it is a backdoor for adding invalid objects.
*
* @param collection the collection to predicate, must not be null
* @param predicate the predicate for the collection, must not be null
* @param <C> the type of objects in the Collection.
* @return a predicated collection backed by the given collection
* @throws IllegalArgumentException if the Collection is null
*/
public static <C> Collection<C> predicatedCollection(Collection<C> collection, Predicate<? super C> predicate) {
return PredicatedCollection.decorate(collection, predicate);
}
/**
* Returns a transformed bag backed by the given collection.
* <p>
* Each object is passed through the transformer as it is added to the
* Collection. It is important not to use the original collection after invoking this
* method, as it is a backdoor for adding untransformed objects.
*
* @param collection the collection to predicate, must not be null
* @param transformer the transformer for the collection, must not be null
* @return a transformed collection backed by the given collection
* @throws IllegalArgumentException if the Collection or Transformer is null
*/
public static <E> Collection<E> transformedCollection(Collection<E> collection, Transformer<? super E, ? extends E> transformer) {
return TransformedCollection.decorate(collection, transformer);
}
/**
* Extract the lone element of the specified Collection.
* @param <E> collection type
* @param collection to read
* @return sole member of collection
* @throws IllegalArgumentException if collection is null/empty or contains more than one element
*/
public static <E> E extractSingleton(Collection<E> collection) {
if (collection == null || collection.size() != 1) {
throw new IllegalArgumentException("Can extract singleton only when collection size == 1");
}
return collection.iterator().next();
}
}