Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.feilong.lib.collection4.CollectionUtils Maven / Gradle / Ivy
Go to download
feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.
/*
* 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 com.feilong.lib.collection4;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
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.collections4.Equator;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
/**
* Provides utility methods and decorators for {@link Collection} instances.
*
* Various utility methods might put the input objects into a Set/Map/Bag. In case
* the input objects override {@link Object#equals(Object)}, it is mandatory that
* the general contract of the {@link Object#hashCode()} method is maintained.
*
*
* NOTE: From 4.0, method parameters will take {@link Iterable} objects when possible.
*
*
* @since 1.0
*/
public class CollectionUtils{
/**
* Helper class to easily access cardinality properties of two collections.
*
* @param
* the element type
*/
private static class CardinalityHelper {
/** Contains the cardinality for each object in collection A. */
final Map cardinalityA;
/** Contains the cardinality for each object in collection B. */
final Map cardinalityB;
/**
* Create a new CardinalityHelper for two collections.
*
* @param a
* the first collection
* @param b
* the second collection
*/
public CardinalityHelper(final Iterable a, final Iterable b){
cardinalityA = CollectionUtils. getCardinalityMap(a);
cardinalityB = CollectionUtils. getCardinalityMap(b);
}
/**
* Returns the maximum frequency of an object.
*
* @param obj
* the object
* @return the maximum frequency of the object
*/
public final int max(final Object obj){
return Math.max(freqA(obj), freqB(obj));
}
/**
* Returns the minimum frequency of an object.
*
* @param obj
* the object
* @return the minimum frequency of the object
*/
public final int min(final Object obj){
return Math.min(freqA(obj), freqB(obj));
}
/**
* Returns the frequency of this object in collection A.
*
* @param obj
* the object
* @return the frequency of the object in collection A
*/
public int freqA(final Object obj){
return getFreq(obj, cardinalityA);
}
/**
* Returns the frequency of this object in collection B.
*
* @param obj
* the object
* @return the frequency of the object in collection B
*/
public int freqB(final Object obj){
return getFreq(obj, cardinalityB);
}
private static int getFreq(final Object obj,final Map freqMap){
final Integer count = freqMap.get(obj);
if (count != null){
return count.intValue();
}
return 0;
}
}
/**
* Helper class for set-related operations, e.g. union, subtract, intersection.
*
* @param
* the element type
*/
private static class SetOperationCardinalityHelper extends CardinalityHelper implements Iterable{
/** Contains the unique elements of the two collections. */
private final Set elements;
/** Output collection. */
private final List newList;
/**
* Create a new set operation helper from the two collections.
*
* @param a
* the first collection
* @param b
* the second collection
*/
public SetOperationCardinalityHelper(final Iterable a, final Iterable b){
super(a, b);
elements = new HashSet<>();
addAll(elements, a);
addAll(elements, b);
// the resulting list must contain at least each unique element, but may grow
newList = new ArrayList<>(elements.size());
}
@Override
public Iterator iterator(){
return elements.iterator();
}
/**
* Add the object {@code count} times to the result collection.
*
* @param obj
* the object to add
* @param count
* the count
*/
public void setCardinality(final O obj,final int count){
for (int i = 0; i < count; i++){
newList.add(obj);
}
}
/**
* Returns the resulting collection.
*
* @return the result
*/
public Collection 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("rawtypes") // we deliberately use the raw type here
public static final Collection EMPTY_COLLECTION = Collections.emptyList();
/**
* CollectionUtils
should not normally be instantiated.
*/
private CollectionUtils(){
}
/**
* Returns the immutable EMPTY_COLLECTION with generic type safety.
*
* @see #EMPTY_COLLECTION
* @since 4.0
* @param
* the element type
* @return immutable empty collection
*/
@SuppressWarnings("unchecked") // OK, empty collection is compatible with any type
public static Collection emptyCollection(){
return EMPTY_COLLECTION;
}
/**
* Returns an immutable empty collection if the argument is null
,
* or the argument itself otherwise.
*
* @param
* the element type
* @param collection
* the collection, possibly null
* @return an empty collection if the argument is null
*/
public static Collection emptyIfNull(final Collection collection){
return collection == null ? CollectionUtils. emptyCollection() : collection;
}
/**
* Returns a {@link Collection} containing the union of the given
* {@link Iterable}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 Iterable}s.
*
*
* @param a
* the first collection, must not be null
* @param b
* the second collection, must not be null
* @param
* 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 Collection union(final Iterable a,final Iterable b){
final SetOperationCardinalityHelper helper = new SetOperationCardinalityHelper<>(a, b);
for (final O obj : helper){
helper.setCardinality(obj, helper.max(obj));
}
return helper.list();
}
/**
* Returns a {@link Collection} containing the intersection of the given
* {@link Iterable}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 Iterable}s.
*
*
* @param a
* the first collection, must not be null
* @param b
* the second collection, must not be null
* @param
* 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
*/
public static Collection intersection(final Iterable a,final Iterable b){
final SetOperationCardinalityHelper helper = new SetOperationCardinalityHelper<>(a, b);
for (final 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 Iterable}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
* {@code {@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})}
* or
* {@code {@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
* @param
* 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 Collection disjunction(final Iterable a,final Iterable b){
final SetOperationCardinalityHelper helper = new SetOperationCardinalityHelper<>(a, b);
for (final O obj : helper){
helper.setCardinality(obj, helper.max(obj) - helper.min(obj));
}
return helper.list();
}
/**
* Returns true
iff all elements of {@code coll2} are also contained
* in {@code coll1}. The cardinality of values in {@code coll2} is not taken into account,
* which is the same behavior as {@link Collection#containsAll(Collection)}.
*
* In other words, this method returns true
iff the
* {@link #intersection} of coll1 and coll2 has the same cardinality as
* the set of unique values from {@code coll2}. In case {@code coll2} is empty, {@code true}
* will be returned.
*
*
* This method is intended as a replacement for {@link Collection#containsAll(Collection)}
* with a guaranteed runtime complexity of {@code O(n + m)}. Depending on the type of
* {@link Collection} provided, this method will be much faster than calling
* {@link Collection#containsAll(Collection)} instead, though this will come at the
* cost of an additional space complexity O(n).
*
*
* @param coll1
* the first collection, must not be null
* @param coll2
* the second collection, must not be null
* @return true
iff the intersection of the collections has the same cardinality
* as the set of unique elements from the second collection
* @since 4.0
*/
public static boolean containsAll(final Collection coll1,final Collection coll2){
if (coll2.isEmpty()){
return true;
}
final Iterator it = coll1.iterator();
final Set elementsAlreadySeen = new HashSet<>();
for (final Object nextElement : coll2){
if (elementsAlreadySeen.contains(nextElement)){
continue;
}
boolean foundCurrentElement = false;
while (it.hasNext()){
final Object p = it.next();
elementsAlreadySeen.add(p);
if (nextElement == null ? p == null : nextElement.equals(p)){
foundCurrentElement = true;
break;
}
}
if (!foundCurrentElement){
return false;
}
}
return true;
}
/**
* 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
* the type of object in the returned {@link Map}. This is a super type of <I>.
* @param coll
* the collection to get the cardinality map for, must not be null
* @return the populated cardinality map
*/
public static Map getCardinalityMap(final Iterable coll){
final Map count = new HashMap<>();
for (final O obj : coll){
final Integer c = count.get(obj);
if (c == null){
count.put(obj, Integer.valueOf(1));
}else{
count.put(obj, Integer.valueOf(c.intValue() + 1));
}
}
return count;
}
/**
* Returns {@code 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){
final CardinalityHelper helper = new CardinalityHelper<>(a, b);
for (final Object obj : a){
if (helper.freqA(obj) > helper.freqB(obj)){
return false;
}
}
return true;
}
/**
* Returns {@code 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() && CollectionUtils.isSubCollection(a, b);
}
/**
* Returns {@code 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;
}
final CardinalityHelper helper = new CardinalityHelper<>(a, b);
if (helper.cardinalityA.size() != helper.cardinalityB.size()){
return false;
}
for (final Object obj : helper.cardinalityA.keySet()){
if (helper.freqA(obj) != helper.freqB(obj)){
return false;
}
}
return true;
}
/**
* Returns {@code 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 .
*
*
* Note: from version 4.1 onwards this method requires the input
* collections and equator to be of compatible type (using bounded wildcards).
* Providing incompatible arguments (e.g. by casting to their rawtypes)
* will result in a {@code ClassCastException} thrown at runtime.
*
*
* @param
* the element type
* @param a
* the first collection, must not be null
* @param b
* the second collection, must not be null
* @param equator
* the Equator used for testing equality
* @return true
iff the collections contain the same elements with the same cardinalities.
* @throws NullPointerException
* if the equator is null
* @since 4.0
*/
public static boolean isEqualCollection(
final Collection a,
final Collection b,
final Equator equator){
if (equator == null){
throw new NullPointerException("Equator must not be null.");
}
if (a.size() != b.size()){
return false;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
final Transformer transformer = input -> new EquatorWrapper(equator, input);
return isEqualCollection(collect(a, transformer), collect(b, transformer));
}
/**
* Wraps another object and uses the provided Equator to implement
* {@link #equals(Object)} and {@link #hashCode()}.
*
* This class can be used to store objects into a Map.
*
*
* @param
* the element type
* @since 4.0
*/
private static class EquatorWrapper {
private final Equator equator;
private final O object;
public EquatorWrapper(final Equator equator, final O object){
this.equator = equator;
this.object = object;
}
public O getObject(){
return object;
}
@Override
public boolean equals(final Object obj){
if (!(obj instanceof EquatorWrapper)){
return false;
}
@SuppressWarnings("unchecked")
final EquatorWrapper otherObj = (EquatorWrapper) obj;
return equator.equate(object, otherObj.getObject());
}
@Override
public int hashCode(){
return equator.hash(object);
}
}
/**
* Filter the collection by applying a Predicate to each element. If the
* predicate returns false, remove the element.
*
* If the input collection or predicate is null, there is no change made.
*
*
* @param
* the type of object the {@link Iterable} contains
* @param collection
* the collection to get the input from, may be null
* @param predicate
* the predicate to use as a filter, may be null
* @return true if the collection is modified by this call, false otherwise.
*/
public static boolean filter(final Iterable collection,final Predicate predicate){
boolean result = false;
if (collection != null && predicate != null){
for (final Iterator it = collection.iterator(); it.hasNext();){
if (!predicate.evaluate(it.next())){
it.remove();
result = true;
}
}
}
return result;
}
/**
* Filter the collection by applying a Predicate to each element. If the
* predicate returns true, remove the element.
*
* This is equivalent to filter(collection, PredicateUtils.notPredicate(predicate))
* if predicate is != null.
*
*
* If the input collection or predicate is null, there is no change made.
*
*
* @param
* the type of object the {@link Iterable} contains
* @param collection
* the collection to get the input from, may be null
* @param predicate
* the predicate to use as a filter, may be null
* @return true if the collection is modified by this call, false otherwise.
*/
public static boolean filterInverse(final Iterable collection,final Predicate predicate){
return filter(collection, predicate == null ? null : PredicateUtils.notPredicate(predicate));
}
/**
* Transform the collection by applying a Transformer to each element.
*
* If the input collection or transformer is null, there is no change made.
*
*
* 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.
*
*
* 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
* the type of object the {@link Collection} contains
* @param collection
* the {@link Collection} to get the input from, may be null
* @param transformer
* the transformer to perform, may be null
*/
public static void transform(final Collection collection,final Transformer transformer){
if (collection != null && transformer != null){
if (collection instanceof List){
final List list = (List) collection;
for (final ListIterator it = list.listIterator(); it.hasNext();){
it.set(transformer.transform(it.next()));
}
}else{
final Collection resultCollection = collect(collection, transformer);
collection.clear();
collection.addAll(resultCollection);
}
}
}
/**
* Selects all elements from input collection which match the given
* predicate into an output collection.
*
* A null
predicate matches no elements.
*
*
* @param
* the type of object the {@link Iterable} contains
* @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 Collection select(final Iterable inputCollection,final Predicate predicate){
final Collection answer = inputCollection instanceof Collection ? new ArrayList<>(((Collection) inputCollection).size())
: new ArrayList<>();
return select(inputCollection, predicate, answer);
}
/**
* Selects all elements from input collection which match the given
* predicate and adds them to outputCollection.
*
* If the input collection or predicate is null, there is no change to the
* output collection.
*
*
* @param
* the type of object the {@link Iterable} contains
* @param
* the type of the output {@link 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 if the inputCollection
* and predicate or not null
* @return the outputCollection
*/
public static > R select(
final Iterable inputCollection,
final Predicate predicate,
final R outputCollection){
if (inputCollection != null && predicate != null){
for (final O item : inputCollection){
if (predicate.evaluate(item)){
outputCollection.add(item);
}
}
}
return outputCollection;
}
/**
* Selects all elements from inputCollection into an output and rejected collection,
* based on the evaluation of the given predicate.
*
* Elements matching the predicate are added to the outputCollection
,
* all other elements are added to the rejectedCollection
.
*
*
* If the input predicate is null
, no elements are added to
* outputCollection
or rejectedCollection
.
*
*
* Note: calling the method is equivalent to the following code snippet:
*
*
*
* select(inputCollection, predicate, outputCollection);
* selectRejected(inputCollection, predicate, rejectedCollection);
*
*
* @param
* the type of object the {@link Iterable} contains
* @param
* the type of the output {@link 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 selected elements into, may not be null if the
* inputCollection and predicate are not null
* @param rejectedCollection
* the collection to output rejected elements into, may not be null if the
* inputCollection or predicate are not null
* @return the outputCollection
* @since 4.1
*/
public static > R select(
final Iterable inputCollection,
final Predicate predicate,
final R outputCollection,
final R rejectedCollection){
if (inputCollection != null && predicate != null){
for (final O element : inputCollection){
if (predicate.evaluate(element)){
outputCollection.add(element);
}else{
rejectedCollection.add(element);
}
}
}
return outputCollection;
}
/**
* Selects all elements from inputCollection which don't match the given
* predicate into an output collection.
*
* If the input predicate is null
, the result is an empty
* list.
*
*
* @param
* the type of object the {@link Iterable} contains
* @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 not matching the predicate (new list)
* @throws NullPointerException
* if the input collection is null
*/
public static Collection selectRejected(final Iterable inputCollection,final Predicate predicate){
final Collection answer = inputCollection instanceof Collection ? new ArrayList<>(((Collection) inputCollection).size())
: new ArrayList<>();
return selectRejected(inputCollection, predicate, answer);
}
/**
* Selects all elements from inputCollection which don't match the given
* predicate and adds them to outputCollection.
*
* If the input predicate is null
, no elements are added to
* outputCollection
.
*
*
* @param
* the type of object the {@link Iterable} contains
* @param
* the type of the output {@link 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 if the inputCollection
* and predicate or not null
* @return outputCollection
*/
public static > R selectRejected(
final Iterable inputCollection,
final Predicate predicate,
final R outputCollection){
if (inputCollection != null && predicate != null){
for (final O item : inputCollection){
if (!predicate.evaluate(item)){
outputCollection.add(item);
}
}
}
return outputCollection;
}
/**
* Returns a new Collection containing all elements of the input collection
* transformed by the given transformer.
*
* If the input collection or transformer is null, the result is an empty list.
*
*
* @param
* the type of object in the input collection
* @param
* the type of object in the output collection
* @param inputCollection
* the collection to get the input from, may not be null
* @param transformer
* the transformer to use, may be null
* @return the transformed result (new list)
* @throws NullPointerException
* if the input collection is null
*/
public static Collection collect(final Iterable inputCollection,final Transformer transformer){
final Collection answer = inputCollection instanceof Collection ? new ArrayList<>(((Collection) inputCollection).size())
: new ArrayList<>();
return collect(inputCollection, transformer, answer);
}
/**
* Transforms all elements from the input iterator with the given transformer
* and adds them to the output collection.
*
* If the input iterator or transformer is null, the result is an empty list.
*
*
* @param
* the type of object in the input collection
* @param
* the type of object in the output collection
* @param inputIterator
* the iterator to get the input from, may be null
* @param transformer
* the transformer to use, may be null
* @return the transformed result (new list)
*/
public static Collection collect(final Iterator inputIterator,final Transformer transformer){
return collect(inputIterator, transformer, new ArrayList());
}
/**
* Transforms all elements from input collection with the given transformer
* and adds them to the output collection.
*
* If the input collection or transformer is null, there is no change to the
* output collection.
*
*
* @param
* the type of object in the input collection
* @param
* the type of object in the output collection
* @param
* the type of 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 if inputCollection
* and transformer are not null
* @return the output collection with the transformed input added
* @throws NullPointerException
* if the outputCollection is null and both, inputCollection and
* transformer are not null
*/
public static > R collect(
final Iterable inputCollection,
final Transformer transformer,
final R outputCollection){
if (inputCollection != null){
return collect(inputCollection.iterator(), transformer, outputCollection);
}
return outputCollection;
}
/**
* Transforms all elements from the input iterator with the given transformer
* and adds them to the output collection.
*
* If the input iterator or transformer is null, there is no change to the
* output collection.
*
*
* @param
* the type of object in the input collection
* @param
* the type of object in the output collection
* @param
* the type of 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 if inputIterator
* and transformer are not null
* @return the outputCollection with the transformed input added
* @throws NullPointerException
* if the output collection is null and both, inputIterator and
* transformer are not null
*/
public static > R collect(
final Iterator inputIterator,
final Transformer transformer,
final R outputCollection){
if (inputIterator != null && transformer != null){
while (inputIterator.hasNext()){
final I item = inputIterator.next();
final O value = transformer.transform(item);
outputCollection.add(value);
}
}
return outputCollection;
}
//-----------------------------------------------------------------------
/**
* Adds an element to the collection unless the element is null.
*
* @param
* the type of object the {@link Collection} contains
* @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 3.2
*/
public static boolean addIgnoreNull(final Collection collection,final T object){
if (collection == null){
throw new NullPointerException("The collection must not be null");
}
return object != null && 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
* the type of object the {@link Collection} contains
* @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 boolean addAll(final Collection collection,final Iterable iterable){
if (iterable instanceof Collection){
return collection.addAll((Collection) iterable);
}
return addAll(collection, iterable.iterator());
}
/**
* Adds all elements in the iteration to the given collection.
*
* @param
* the type of object the {@link Collection} contains
* @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 boolean addAll(final Collection collection,final Iterator 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
* the type of object the {@link Collection} contains
* @param collection
* the collection to add to, must not be null
* @param enumeration
* the enumeration of elements to add, must not be null
* @return {@code true} if the collections was changed, {@code false} otherwise
* @throws NullPointerException
* if the collection or enumeration is null
*/
public static boolean addAll(final Collection collection,final Enumeration enumeration){
boolean changed = false;
while (enumeration.hasMoreElements()){
changed |= collection.add(enumeration.nextElement());
}
return changed;
}
/**
* Adds all elements in the array to the given collection.
*
* @param
* the type of object the {@link Collection} contains
* @param collection
* the collection to add to, must not be null
* @param elements
* the array of elements to add, must not be null
* @return {@code true} if the collection was changed, {@code false} otherwise
* @throws NullPointerException
* if the collection or array is null
*/
@SafeVarargs
public static boolean addAll(final Collection collection,final C...elements){
boolean changed = false;
for (final C element : elements){
changed |= collection.add(element);
}
return changed;
}
/**
* Ensures an index is not negative.
*
* @param index
* the index to check.
* @throws IndexOutOfBoundsException
* if the index is negative.
*/
static void checkIndexBounds(final int index){
if (index < 0){
throw new IndexOutOfBoundsException("Index cannot be negative: " + index);
}
}
/**
* Returns the index
-th value in object
, throwing
* IndexOutOfBoundsException
if there is no such element or
* IllegalArgumentException
if object
is not an
* instance of one of the supported types.
*
* The supported types, and associated semantics are:
*
*
* Map -- the value returned is the Map.Entry
in position
* index
in the map's entrySet
iterator,
* if there is such an entry.
* List -- this method is equivalent to the list's get method.
* Array -- the index
-th array entry is returned,
* if there is such an entry; otherwise an IndexOutOfBoundsException
* is thrown.
* Collection -- the value returned is the index
-th object
* returned by the collection's default iterator, if there is such an element.
* Iterator or Enumeration -- the value returned is the
* index
-th object in the Iterator/Enumeration, if there
* is such an element. The Iterator/Enumeration is advanced to
* index
(or to the end, if index
exceeds the
* number of entries) as a side effect of this method.
*
*
* @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(final Object object,final int index){
final int i = index;
if (i < 0){
throw new IndexOutOfBoundsException("Index cannot be negative: " + i);
}
if (object instanceof Map){
final Map map = (Map) object;
final Iterator iterator = map.entrySet().iterator();
return IteratorUtils.get(iterator, i);
}
if (object instanceof Object[]){
return ((Object[]) object)[i];
}
if (object instanceof Iterator){
final Iterator it = (Iterator) object;
return IteratorUtils.get(it, i);
}
if (object instanceof Iterable){
final Iterable iterable = (Iterable) object;
return IterableUtils.get(iterable, i);
}
if (object instanceof Enumeration){
final Enumeration it = (Enumeration) object;
return EnumerationUtils.get(it, i);
}
if (object == null){
throw new IllegalArgumentException("Unsupported object type: null");
}
try{
return Array.get(object, i);
}catch (final IllegalArgumentException ex){
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
/**
* Returns the index
-th Map.Entry
in the map
's entrySet
,
* throwing IndexOutOfBoundsException
if there is no such element.
*
* @param
* the key type in the {@link Map}
* @param
* the key type in the {@link Map}
* @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 Map.Entry get(final Map map,final int index){
checkIndexBounds(index);
return IterableUtils.get(map.entrySet(), index);
}
/**
* Gets the size of the collection/iterator specified.
*
* This method can handles objects as follows
*
*
* Collection - the collection size
* Map - the map size
* Array - the array size
* Iterator - the number of elements remaining in the iterator
* Enumeration - the number of elements remaining in the enumeration
*
*
* @param object
* the object to get the size of, may be null
* @return the size of the specified collection or 0 if the object was null
* @throws IllegalArgumentException
* thrown if object is not recognized
* @since 3.1
*/
public static int size(final Object object){
if (object == null){
return 0;
}
if (object instanceof Map){
return ((Map) object).size();
}
if (object instanceof Collection){
return ((Collection) object).size();
}
if (object instanceof Iterable){
return IterableUtils.size((Iterable) object);
}
if (object instanceof Object[]){
return ((Object[]) object).length;
}
if (object instanceof Iterator){
return IteratorUtils.size((Iterator) object);
}
if (object instanceof Enumeration){
int total = 0;
final Enumeration it = (Enumeration) object;
while (it.hasMoreElements()){
total++;
it.nextElement();
}
return total;
}
try{
return Array.getLength(object);
}catch (final IllegalArgumentException ex){
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
/**
* Checks if the specified collection/array/iterator is empty.
*
* This method can handles objects as follows
*
*
* Collection - via collection isEmpty
* Map - via map isEmpty
* Array - using array size
* Iterator - via hasNext
* Enumeration - via hasMoreElements
*
*
* Note: This method is named to avoid clashing with
* {@link #isEmpty(Collection)}.
*
*
* @param object
* the object to get the size of, may be null
* @return true if empty or null
* @throws IllegalArgumentException
* thrown if object is not recognized
* @since 3.2
*/
public static boolean sizeIsEmpty(final Object object){
if (object == null){
return true;
}else if (object instanceof Collection){
return ((Collection) object).isEmpty();
}else if (object instanceof Iterable){
return IterableUtils.isEmpty((Iterable) object);
}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{
try{
return Array.getLength(object) == 0;
}catch (final IllegalArgumentException ex){
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
}
//-----------------------------------------------------------------------
/**
* 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
* @since 3.2
*/
public static boolean isEmpty(final 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
* @since 3.2
*/
public static boolean isNotEmpty(final Collection coll){
return !isEmpty(coll);
}
//-----------------------------------------------------------------------
/**
* Reverses the order of the given array.
*
* @param array
* the array to reverse
*/
public static void reverseArray(final 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 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);
.
*
* This implementation iterates over collection
, checking each element in
* turn to see if it's contained in retain
. If it's contained, it's added
* to the returned list. As a consequence, it is advised to use a collection type for
* retain
that provides a fast (e.g. O(1)) implementation of
* {@link Collection#contains(Object)}.
*
*
* @param
* the type of object the {@link Collection} contains
* @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
* @since 3.2
*/
public static Collection retainAll(final Collection collection,final Collection retain){
return ListUtils.retainAll(collection, retain);
}
/**
* 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);
.
*
* Moreover this method uses an {@link Equator} instead of
* {@link Object#equals(Object)} to determine the equality of the elements
* in collection
and retain
. Hence this method is
* useful in cases where the equals behavior of an object needs to be
* modified without changing the object itself.
*
*
* @param
* the type of object the {@link Collection} contains
* @param collection
* the collection whose contents are the target of the {@code retainAll} operation
* @param retain
* the collection containing the elements to be retained in the returned collection
* @param equator
* the Equator used for testing equality
* @return a Collection
containing all the elements of collection
* that occur at least once in retain
according to the equator
* @throws NullPointerException
* if any of the parameters is null
* @since 4.1
*/
public static Collection retainAll(
final Iterable collection,
final Iterable retain,
final Equator equator){
final Transformer> transformer = input -> new EquatorWrapper<>(equator, input);
final Set> retainSet = collect(retain, transformer, new HashSet>());
final List list = new ArrayList<>();
for (final E element : collection){
if (retainSet.contains(new EquatorWrapper<>(equator, element))){
list.add(element);
}
}
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);
.
*
* This implementation iterates over collection
, checking each element in
* turn to see if it's contained in remove
. If it's not contained, it's added
* to the returned list. As a consequence, it is advised to use a collection type for
* remove
that provides a fast (e.g. O(1)) implementation of
* {@link Collection#contains(Object)}.
*
*
* @param
* the type of object the {@link Collection} contains
* @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
* @since 4.0 (method existed in 3.2 but was completely broken)
*/
public static Collection removeAll(final Collection collection,final Collection remove){
return ListUtils.removeAll(collection, remove);
}
/**
* Removes all elements in remove
from collection
.
* That is, this method returns a collection containing all the elements in
* collection
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)
.
*
* Moreover this method uses an {@link Equator} instead of
* {@link Object#equals(Object)} to determine the equality of the elements
* in collection
and remove
. Hence this method is
* useful in cases where the equals behavior of an object needs to be
* modified without changing the object itself.
*
*
* @param
* the type of object the {@link Collection} contains
* @param collection
* the collection from which items are removed (in the returned collection)
* @param remove
* the items to be removed from the returned collection
* @param equator
* the Equator used for testing equality
* @return a Collection
containing all the elements of collection
* except any element that if equal according to the equator
* @throws NullPointerException
* if any of the parameters is null
* @since 4.1
*/
public static Collection removeAll(
final Iterable collection,
final Iterable remove,
final Equator equator){
final Transformer> transformer = input -> new EquatorWrapper<>(equator, input);
final Set> removeSet = collect(remove, transformer, new HashSet>());
final List list = new ArrayList<>();
for (final E element : collection){
if (!removeSet.contains(new EquatorWrapper<>(equator, element))){
list.add(element);
}
}
return list;
}
/**
* Extract the lone element of the specified Collection.
*
* @param
* collection type
* @param collection
* to read
* @return sole member of collection
* @throws NullPointerException
* if collection is null
* @throws IllegalArgumentException
* if collection is empty or contains more than one element
* @since 4.0
*/
public static E extractSingleton(final Collection collection){
if (collection == null){
throw new NullPointerException("Collection must not be null.");
}
if (collection.size() != 1){
throw new IllegalArgumentException("Can extract singleton only when collection size == 1");
}
return collection.iterator().next();
}
}