All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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.

There is a newer version: 4.0.8
Show newest version
/*
 * 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(); } }