commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bay...@apache.org
Subject svn commit: r815042 - /commons/proper/collections/trunk/src/java/org/apache/commons/collections/CollectionUtils.java
Date Tue, 15 Sep 2009 05:54:55 GMT
Author: bayard
Date: Tue Sep 15 05:54:54 2009
New Revision: 815042

URL: http://svn.apache.org/viewvc?rev=815042&view=rev
Log:
Merging from -r468106:814127 of collections_jdk5_branch - namely where this code was generified; mostly in r738956.

Also see the following revisions:

    ------------------------------------------------------------------------
    r814063 | sebb | 2009-09-11 15:25:29 -0700 (Fri, 11 Sep 2009) | 1 line
    
    Javadoc typos; fix internal raw types
    ------------------------------------------------------------------------
    r814050 | sebb | 2009-09-11 15:01:25 -0700 (Fri, 11 Sep 2009) | 1 line
    
    Some minor Javadoc fixes
    ------------------------------------------------------------------------
    r813951 | mbenson | 2009-09-11 10:48:55 -0700 (Fri, 11 Sep 2009) | 1 line
    
    [COLLECTIONS-286] CollectionsUtils.extractSingleton
    ------------------------------------------------------------------------
    r813925 | mbenson | 2009-09-11 10:05:31 -0700 (Fri, 11 Sep 2009) | 1 line
    
    [COLLECTIONS-182] return Closure from CollectionUtils.forAllDo
    ------------------------------------------------------------------------
    r648113 | skestle | 2008-04-14 21:32:39 -0700 (Mon, 14 Apr 2008) | 1 line
    
    Updated CollectionUtils to return the same type of Collection that is passed into select(), reject() and collect()
    ------------------------------------------------------------------------
    r593968 | skestle | 2007-11-11 13:59:08 -0800 (Sun, 11 Nov 2007) | 1 line
    
    Missed 1 variable rename causing test to fail for COLLECTIONS-245
    ------------------------------------------------------------------------
    r593964 | skestle | 2007-11-11 13:44:41 -0800 (Sun, 11 Nov 2007) | 2 lines
    
    Applied (most of) Brian Egge's clean up patch of previous commit for COLLECTIONS-245 - thanks! (And we're at 100%)
    
    ------------------------------------------------------------------------
    r593144 | skestle | 2007-11-08 04:21:55 -0800 (Thu, 08 Nov 2007) | 3 lines
    
    Updated CollectionUtils and test.  Probably 80-90% complete for generics.  Very open to review / patches.
    
    Jira: COLLECTIONS-245
    ------------------------------------------------------------------------
    r562381 | skestle | 2007-08-03 01:15:35 -0700 (Fri, 03 Aug 2007) | 1 line
    
    Extracted private CollectionUtils.CardinalityHelper classes to allow easier generic refactoring/maintenance and code readability.
    ------------------------------------------------------------------------
    r561846 | niallp | 2007-08-01 08:53:19 -0700 (Wed, 01 Aug 2007) | 1 line
    
    Test commit (just remove a trailing space) on Collections JDK5 Branch
    ------------------------------------------------------------------------
    r471166 | scolebourne | 2006-11-04 03:33:22 -0800 (Sat, 04 Nov 2006) | 1 line
    
    Removed Typed* containers such as TypedList and TypedMap as generics now provides type safety
    ------------------------------------------------------------------------
    r468690 | scolebourne | 2006-10-28 06:03:11 -0700 (Sat, 28 Oct 2006) | 1 line
    
    COLLECTIONS-229 - Remove deprecated classes and code
    ------------------------------------------------------------------------

Modified:
    commons/proper/collections/trunk/src/java/org/apache/commons/collections/CollectionUtils.java

Modified: commons/proper/collections/trunk/src/java/org/apache/commons/collections/CollectionUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/java/org/apache/commons/collections/CollectionUtils.java?rev=815042&r1=815041&r2=815042&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/java/org/apache/commons/collections/CollectionUtils.java (original)
+++ commons/proper/collections/trunk/src/java/org/apache/commons/collections/CollectionUtils.java Tue Sep 15 05:54:54 2009
@@ -31,12 +31,12 @@
 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.TypedCollection;
 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$
@@ -54,11 +54,72 @@
  * @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 {
 
-    /** Constant to avoid repeated object creation */
-    private static final Integer INTEGER_ONE = new Integer(1);
+    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.
@@ -66,7 +127,8 @@
      * this purpose. However they could be cast to Set or List which might be
      * undesirable. This implementation only implements Collection.
      */
-    public static final Collection EMPTY_COLLECTION = UnmodifiableCollection.decorate(new ArrayList());
+    @SuppressWarnings("unchecked")
+    public static final Collection EMPTY_COLLECTION = UnmodifiableCollection.decorate(new ArrayList<Object>());
 
     /**
      * <code>CollectionUtils</code> should not normally be instantiated.
@@ -75,95 +137,89 @@
     }
 
     /**
-     * Returns a {@link Collection} containing the union
-     * of the given {@link Collection}s.
+     * 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.
+     * The cardinality of each element in the returned {@link Collection} will
+     * be equal to the maximum of the cardinality of that element in the two
+     * given {@link Collection}s.
      *
-     * @param a  the first collection, must not be null
-     * @param b  the second collection, must not be null
-     * @return  the union of the two collections
+     * @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 Collection union(final Collection a, final Collection b) {
-        ArrayList list = new ArrayList();
-        Map mapa = getCardinalityMap(a);
-        Map mapb = getCardinalityMap(b);
-        Set elts = new HashSet(a);
-        elts.addAll(b);
-        Iterator it = elts.iterator();
-        while(it.hasNext()) {
-            Object obj = it.next();
-            for(int i=0,m=Math.max(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) {
-                list.add(obj);
-            }
+    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 list;
+        return helper.list();
     }
 
     /**
-     * Returns a {@link Collection} containing the intersection
-     * of the given {@link Collection}s.
+     * 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.
+     * 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 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 Collection intersection(final Collection a, final Collection b) {
-        ArrayList list = new ArrayList();
-        Map mapa = getCardinalityMap(a);
-        Map mapb = getCardinalityMap(b);
-        Set elts = new HashSet(a);
-        elts.addAll(b);
-        Iterator it = elts.iterator();
-        while(it.hasNext()) {
-            Object obj = it.next();
-            for(int i=0,m=Math.min(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) {
-                list.add(obj);
-            }
+    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 list;
+        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
+     * 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 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 Collection disjunction(final Collection a, final Collection b) {
-        ArrayList list = new ArrayList();
-        Map mapa = getCardinalityMap(a);
-        Map mapb = getCardinalityMap(b);
-        Set elts = new HashSet(a);
-        elts.addAll(b);
-        Iterator it = elts.iterator();
-        while(it.hasNext()) {
-            Object obj = it.next();
-            for(int i=0,m=((Math.max(getFreq(obj,mapa),getFreq(obj,mapb)))-(Math.min(getFreq(obj,mapa),getFreq(obj,mapb))));i<m;i++) {
-                list.add(obj);
-            }
+    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 list;
+        return helper.list();
     }
 
     /**
@@ -174,13 +230,16 @@
      *
      * @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 Collection subtract(final Collection a, final Collection b) {
-        ArrayList list = new ArrayList( a );
-        for (Iterator it = b.iterator(); it.hasNext();) {
-            list.remove(it.next());
+    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;
     }
@@ -190,23 +249,23 @@
      * <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) {
+    public static boolean containsAny(final Collection<?> coll1, final Collection<?> coll2) {
         if (coll1.size() < coll2.size()) {
-            for (Iterator it = coll1.iterator(); it.hasNext();) {
-                if (coll2.contains(it.next())) {
+            for (Object aColl1 : coll1) {
+                if (coll2.contains(aColl1)) {
                     return true;
                 }
             }
         } else {
-            for (Iterator it = coll2.iterator(); it.hasNext();) {
-                if (coll1.contains(it.next())) {
+            for (Object aColl2 : coll2) {
+                if (coll1.contains(aColl2)) {
                     return true;
                 }
             }
@@ -221,19 +280,23 @@
      * <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 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 Map getCardinalityMap(final Collection coll) {
-        Map count = new HashMap();
-        for (Iterator it = coll.iterator(); it.hasNext();) {
-            Object obj = it.next();
-            Integer c = (Integer) (count.get(obj));
+    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,INTEGER_ONE);
+                count.put(obj, 1);
             } else {
-                count.put(obj,new Integer(c.intValue() + 1));
+                count.put(obj, c + 1);
             }
         }
         return count;
@@ -241,23 +304,20 @@
 
     /**
      * 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>.
+     * 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
+     * @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) {
-        Map mapa = getCardinalityMap(a);
-        Map mapb = getCardinalityMap(b);
-        Iterator it = a.iterator();
-        while (it.hasNext()) {
-            Object obj = it.next();
-            if (getFreq(obj, mapa) > getFreq(obj, mapb)) {
+    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;
             }
         }
@@ -274,7 +334,7 @@
      * <p>
      * The implementation assumes
      * <ul>
-     *    <li><code>a.size()</code> and <code>b.size()</code> represent the 
+     *    <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>
@@ -285,8 +345,8 @@
      * @see #isSubCollection
      * @see Collection#containsAll
      */
-    public static boolean isProperSubCollection(final Collection a, final Collection b) {
-        return (a.size() < b.size()) && CollectionUtils.isSubCollection(a,b);
+    public static boolean isProperSubCollection(final Collection<?> a, final Collection<?> b) {
+        return (a.size() < b.size()) && CollectionUtils.isSubCollection(a, b);
     }
 
     /**
@@ -301,51 +361,47 @@
      * @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) {
+    public static boolean isEqualCollection(final Collection<?> a, final Collection<?> b) {
         if(a.size() != b.size()) {
             return false;
-        } else {
-            Map mapa = getCardinalityMap(a);
-            Map mapb = getCardinalityMap(b);
-            if(mapa.size() != mapb.size()) {
+        }
+        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;
-            } else {
-                Iterator it = mapa.keySet().iterator();
-                while(it.hasNext()) {
-                    Object obj = it.next();
-                    if(getFreq(obj,mapa) != getFreq(obj,mapb)) {
-                        return false;
-                    }
-                }
-                return true;
             }
         }
+        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 collection to search
+     * @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 int cardinality(Object obj, final Collection coll) {
-        if (coll instanceof Set) {
-            return (coll.contains(obj) ? 1 : 0);
+    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) coll).getCount(obj);
+        if (coll instanceof Bag<?>) {
+            return ((Bag<? super O>) coll).getCount(obj);
         }
         int count = 0;
         if (obj == null) {
-            for (Iterator it = coll.iterator();it.hasNext();) {
-                if (it.next() == null) {
+            for (Object element : coll) {
+                if (element == null) {
                     count++;
                 }
             }
         } else {
-            for (Iterator it = coll.iterator();it.hasNext();) {
-                if (obj.equals(it.next())) {
+            for (Object element : coll) {
+                if (obj.equals(element)) {
                     count++;
                 }
             }
@@ -353,20 +409,19 @@
         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 
+     * 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 Object find(Collection collection, Predicate predicate) {
+    public static <T> T find(Collection<T> collection, Predicate<? super T> predicate) {
         if (collection != null && predicate != null) {
-            for (Iterator iter = collection.iterator(); iter.hasNext();) {
-                Object item = iter.next();
+            for (T item : collection) {
                 if (predicate.evaluate(item)) {
                     return item;
                 }
@@ -374,87 +429,99 @@
         }
         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
+     *
+     * @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 void forAllDo(Collection collection, Closure closure) {
+    public static <T, C extends Closure<? super T>> C forAllDo(Collection<T> collection, C closure) {
         if (collection != null && closure != null) {
-            for (Iterator it = collection.iterator(); it.hasNext();) {
-                closure.execute(it.next());
+            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
+     *
+     * @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 void filter(Collection collection, Predicate predicate) {
+    public static <T> void filter(Iterable<T> collection, Predicate<? super T> predicate) {
         if (collection != null && predicate != null) {
-            for (Iterator it = collection.iterator(); it.hasNext();) {
-                if (predicate.evaluate(it.next()) == false) {
+            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.  
+     * 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 collection to get the input from, may be null
-     * @param transformer  the transformer to perform, may be null
+     * 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 void transform(Collection collection, Transformer transformer) {
+    public static <C> void transform(Collection<C> collection,
+            Transformer<? super C, ? extends C> transformer) {
         if (collection != null && transformer != null) {
-            if (collection instanceof List) {
-                List list = (List) collection;
-                for (ListIterator it = list.listIterator(); it.hasNext();) {
+            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 resultCollection = collect(collection, transformer);
+                Collection<C> resultCollection = collect(collection, transformer);
                 collection.clear();
                 collection.addAll(resultCollection);
             }
         }
     }
 
-    /** 
-     * Counts the number of elements in the input collection that match the predicate.
+    /**
+     * 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 inputCollection  the collection to get the input from, may be null
-     * @param predicate  the predicate to use, may be null
+     *
+     * @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 int countMatches(Collection inputCollection, Predicate predicate) {
+    public static <C> int countMatches(Iterable<C> input, Predicate<? super C> predicate) {
         int count = 0;
-        if (inputCollection != null && predicate != null) {
-            for (Iterator it = inputCollection.iterator(); it.hasNext();) {
-                if (predicate.evaluate(it.next())) {
+        if (input != null && predicate != null) {
+            for (C o : input) {
+                if (predicate.evaluate(o)) {
                     count++;
                 }
             }
@@ -462,19 +529,23 @@
         return count;
     }
 
-    /** 
-     * Answers true if a predicate is true for at least one element of a collection.
+    /**
+     * 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 collection the collection 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 boolean exists(Collection collection, Predicate predicate) {
-        if (collection != null && predicate != null) {
-            for (Iterator it = collection.iterator(); it.hasNext();) {
-                if (predicate.evaluate(it.next())) {
+     *
+     * @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;
                 }
             }
@@ -482,154 +553,191 @@
         return false;
     }
 
-    /** 
-     * Selects all elements from input collection which match the given predicate
-     * into an output collection.
+    /**
+     * 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
+     *
+     * @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
+     * @throws NullPointerException
+     *             if the input collection is null
      */
-    public static Collection select(Collection inputCollection, Predicate predicate) {
-        ArrayList answer = new ArrayList(inputCollection.size());
-        select(inputCollection, predicate, answer);
-        return answer;
+    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.
+    /**
+     * 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 
+     * 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
+     *
+     * @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 void select(Collection inputCollection, Predicate predicate, Collection 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 (Iterator iter = inputCollection.iterator(); iter.hasNext();) {
-                Object item = iter.next();
+            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.
+     * 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
+     * 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
+     * @throws NullPointerException
+     *             if the input collection is null
      */
-    public static Collection selectRejected(Collection inputCollection, Predicate predicate) {
-        ArrayList answer = new ArrayList(inputCollection.size());
-        selectRejected(inputCollection, predicate, answer);
-        return answer;
+    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.
+
+    /**
+     * 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
+     * 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 void selectRejected(Collection inputCollection, Predicate predicate, Collection 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 (Iterator iter = inputCollection.iterator(); iter.hasNext();) {
-                Object item = iter.next();
-                if (predicate.evaluate(item) == false) {
+            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.
+
+    /**
+     * 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 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
+     * @throws NullPointerException
+     *             if the input collection is null
      */
-    public static Collection collect(Collection inputCollection, Transformer transformer) {
-        ArrayList answer = new ArrayList(inputCollection.size());
+    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 
+
+    /**
+     * 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
+     * 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 Collection collect(Iterator inputIterator, Transformer transformer) {
-        ArrayList answer = new ArrayList();
+    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 
+
+    /**
+     * 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 
+     * 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 Collection collect(Collection inputCollection, final Transformer transformer, final Collection outputCollection) {
+    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 
+    /**
+     * 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 
+     * 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
      */
-    public static Collection collect(Iterator inputIterator, final Transformer transformer, final Collection outputCollection) {
+    //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()) {
-                Object item = inputIterator.next();
-                Object value = transformer.transform(item);
+                I item = inputIterator.next();
+                O value = transformer.transform(item);
                 outputCollection.add(value);
             }
         }
@@ -639,187 +747,168 @@
     //-----------------------------------------------------------------------
     /**
      * 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 boolean addIgnoreNull(Collection collection, Object object) {
+    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
-     * @throws NullPointerException if the collection or iterator is null
+     *
+     * @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 void addAll(Collection collection, Iterator iterator) {
+    public static <C> boolean addAll(Collection<C> collection, Iterator<? extends C> iterator) {
+        boolean changed = false;
         while (iterator.hasNext()) {
-            collection.add(iterator.next());
+            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
      */
-    public static void addAll(Collection collection, Enumeration enumeration) {
+     //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
+     *
+     * @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 void addAll(Collection collection, Object[] elements) {
+    public static <C> void addAll(Collection<C> collection, C[] elements) {
         for (int i = 0, size = elements.length; i < size; i++) {
             collection.add(elements[i]);
         }
-    }    
-    
-    /**
-     * Given an Object, and an index, returns the nth value in the
-     * object.
-     * <ul>
-     * <li>If obj is a Map, returns the nth value from the <b>keySet</b> iterator, unless 
-     *     the Map contains an Integer key with integer value = idx, in which case the
-     *     corresponding map entry value is returned.  If idx exceeds the number of entries in
-     *     the map, an empty Iterator is returned.
-     * <li>If obj is a List or an array, returns the nth value, throwing IndexOutOfBoundsException,
-     *     ArrayIndexOutOfBoundsException, resp. if the nth value does not exist.
-     * <li>If obj is an iterator, enumeration or Collection, returns the nth value from the iterator,
-     *     returning an empty Iterator (resp. Enumeration) if the nth value does not exist.
-     * <li>Returns the original obj if it is null or not a Collection or Iterator.
-     * </ul>
-     * 
-     * @param obj  the object to get an index of, may be null
-     * @param idx  the index to get
-     * @throws IndexOutOfBoundsException
-     * @throws ArrayIndexOutOfBoundsException
-     *
-     * @deprecated use {@link #get(Object, int)} instead. Will be removed in v4.0
-     */
-    public static Object index(Object obj, int idx) {
-        return index(obj, new Integer(idx));
     }
-    
+
     /**
-     * Given an Object, and a key (index), returns the value associated with
-     * that key in the Object. The following checks are made:
-     * <ul>
-     * <li>If obj is a Map, use the index as a key to get a value. If no match continue.
-     * <li>Check key is an Integer. If not, return the object passed in.
-     * <li>If obj is a Map, get the nth value from the <b>keySet</b> iterator.
-     *     If the Map has fewer than n entries, return an empty Iterator.
-     * <li>If obj is a List or an array, get the nth value, throwing IndexOutOfBoundsException,
-     *     ArrayIndexOutOfBoundsException, resp. if the nth value does not exist.
-     * <li>If obj is an iterator, enumeration or Collection, get the nth value from the iterator,
-     *     returning an empty Iterator (resp. Enumeration) if the nth value does not exist.
-     * <li>Return the original obj.
-     * </ul>
-     * 
-     * @param obj  the object to get an index of
+     * 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
-     * @throws ArrayIndexOutOfBoundsException
-     *
-     * @deprecated use {@link #get(Object, int)} instead. Will be removed in v4.0
+     * @throws IndexOutOfBoundsException if the index is invalid
+     * @throws IllegalArgumentException if the object type is invalid
      */
-    public static Object index(Object obj, Object index) {
-        if(obj instanceof Map) {
-            Map map = (Map)obj;
-            if(map.containsKey(index)) {
-                return map.get(index);
-            }
-        }
-        int idx = -1;
-        if(index instanceof Integer) {
-            idx = ((Integer)index).intValue();
-        }
-        if(idx < 0) {
-            return obj;
-        } 
-        else if(obj instanceof Map) {
-            Map map = (Map)obj;
-            Iterator iterator = map.keySet().iterator();
-            return index(iterator, idx);
-        } 
-        else if(obj instanceof List) {
-            return ((List)obj).get(idx);
-        } 
-        else if(obj instanceof Object[]) {
-            return ((Object[])obj)[idx];
-        } 
-        else if(obj instanceof Enumeration) {
-            Enumeration it = (Enumeration)obj;
-            while(it.hasMoreElements()) {
-                idx--;
-                if(idx == -1) {
-                    return it.nextElement();
-                } else {
-                    it.nextElement();
+    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();
                 }
-            }
-        } 
-        else if(obj instanceof Iterator) {
-            return index((Iterator)obj, idx);
-        }
-        else if(obj instanceof Collection) {
-            Iterator iterator = ((Collection)obj).iterator();
-            return index(iterator, idx);
-        }
-        return obj;
-    }
-
-    private static Object index(Iterator iterator, int idx) {
-        while(iterator.hasNext()) {
-            idx--;
-            if(idx == -1) {
-                return iterator.next();
-            } else {
                 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);
         }
-        return iterator;
     }
-    
+
+    /**
+     * 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 
+     * <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, 
+     * <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, 
+     * <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 
+     * <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 
+     *      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
@@ -827,54 +916,66 @@
      * @throws IllegalArgumentException if the object type is invalid
      */
     public static Object get(Object object, int index) {
-        if (index < 0) {
-            throw new IndexOutOfBoundsException("Index cannot be negative: " + index);
-        }
-        if (object instanceof Map) {
-            Map map = (Map) object;
-            Iterator iterator = map.entrySet().iterator();
-            return get(iterator, index);
-        } else if (object instanceof List) {
-            return ((List) object).get(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)[index];
-        } else if (object instanceof Iterator) {
-            Iterator it = (Iterator) object;
+            return ((Object[]) object)[i];
+        } else if (object instanceof Iterator<?>) {
+            Iterator<?> it = (Iterator<?>) object;
             while (it.hasNext()) {
-                index--;
-                if (index == -1) {
+                i--;
+                if (i == -1) {
                     return it.next();
-                } else {
-                    it.next();
                 }
+                it.next();
             }
-            throw new IndexOutOfBoundsException("Entry does not exist: " + index);
-        } else if (object instanceof Collection) {
-            Iterator iterator = ((Collection) object).iterator();
-            return get(iterator, index);
-        } else if (object instanceof Enumeration) {
-            Enumeration it = (Enumeration) object;
+            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()) {
-                index--;
-                if (index == -1) {
+                i--;
+                if (i == -1) {
                     return it.nextElement();
                 } else {
                     it.nextElement();
                 }
             }
-            throw new IndexOutOfBoundsException("Entry does not exist: " + index);
+            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, index);
+                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
@@ -885,7 +986,7 @@
      * <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, may be null
      * @return the size of the specified collection or 0 if the object was null
      * @throws IllegalArgumentException thrown if object is not recognised
@@ -896,20 +997,20 @@
             return 0;
         }
         int total = 0;
-        if (object instanceof Map) {
-            total = ((Map) object).size();
-        } else if (object instanceof Collection) {
-            total = ((Collection) object).size();
+        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;
+        } else if (object instanceof Iterator<?>) {
+            Iterator<?> it = (Iterator<?>) object;
             while (it.hasNext()) {
                 total++;
                 it.next();
             }
-        } else if (object instanceof Enumeration) {
-            Enumeration it = (Enumeration) object;
+        } else if (object instanceof Enumeration<?>) {
+            Enumeration<?> it = (Enumeration<?>) object;
             while (it.hasMoreElements()) {
                 total++;
                 it.nextElement();
@@ -923,7 +1024,7 @@
         }
         return total;
     }
-    
+
     /**
      * Checks if the specified collection/array/iterator is empty.
      * <p>
@@ -938,7 +1039,7 @@
      * <p>
      * 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 recognised
@@ -947,16 +1048,16 @@
     public static boolean sizeIsEmpty(Object object) {
         if (object == null) {
             return true;
-        } else if (object instanceof Collection) {
-            return ((Collection) object).isEmpty();
-        } else if (object instanceof Map) {
-            return ((Map) object).isEmpty();
+        } else 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 instanceof Iterator<?>) {
+            return ((Iterator<?>) object).hasNext() == false;
+        } else if (object instanceof Enumeration<?>) {
+            return ((Enumeration<?>) object).hasMoreElements() == false;
         } else {
             try {
                 return Array.getLength(object) == 0;
@@ -971,12 +1072,12 @@
      * 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) {
+    public static boolean isEmpty(Collection<?> coll) {
         return (coll == null || coll.isEmpty());
     }
 
@@ -984,19 +1085,19 @@
      * 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 !CollectionUtils.isEmpty(coll);
+    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) {
@@ -1013,14 +1114,6 @@
         }
     }
 
-    private static final int getFreq(final Object obj, final Map freqMap) {
-        Integer count = (Integer) freqMap.get(obj);
-        if (count != null) {
-            return count.intValue();
-        }
-        return 0;
-    }
-
     /**
      * Returns true if no more elements can be added to the Collection.
      * <p>
@@ -1036,17 +1129,17 @@
      * @return true if the BoundedCollection is full
      * @throws NullPointerException if the collection is null
      */
-    public static boolean isFull(Collection coll) {
+    @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();
+            return ((BoundedCollection<?>) coll).isFull();
         }
         try {
-            BoundedCollection bcoll = UnmodifiableBoundedCollection.decorateUsing(coll);
+            BoundedCollection<?> bcoll = UnmodifiableBoundedCollection.decorateUsing((Collection<Object>) coll);
             return bcoll.isFull();
-            
         } catch (IllegalArgumentException ex) {
             return false;
         }
@@ -1067,17 +1160,17 @@
      * @return the maximum size of the BoundedCollection, -1 if no maximum size
      * @throws NullPointerException if the collection is null
      */
-    public static int maxSize(Collection coll) {
+    @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();
+            return ((BoundedCollection<?>) coll).maxSize();
         }
         try {
-            BoundedCollection bcoll = UnmodifiableBoundedCollection.decorateUsing(coll);
+            BoundedCollection<?> bcoll = UnmodifiableBoundedCollection.decorateUsing((Collection<Object>) coll);
             return bcoll.maxSize();
-            
         } catch (IllegalArgumentException ex) {
             return -1;
         }
@@ -1091,7 +1184,7 @@
      * 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>
@@ -1099,7 +1192,7 @@
      * @throws NullPointerException if either parameter is null
      * @since Commons Collections 3.2
      */
-    public static Collection retainAll(Collection collection, Collection retain) {
+    public static <C> Collection<C> retainAll(Collection<C> collection, Collection<?> retain) {
         return ListUtils.retainAll(collection, retain);
     }
 
@@ -1111,7 +1204,7 @@
      * 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
@@ -1119,7 +1212,7 @@
      * @throws NullPointerException if either parameter is null
      * @since Commons Collections 3.3 (method existed in 3.2 but was completely broken)
      */
-    public static Collection removeAll(Collection collection, Collection remove) {
+    public static <E> Collection<E> removeAll(Collection<E> collection, Collection<?> remove) {
         return ListUtils.removeAll(collection, remove);
     }
 
@@ -1127,9 +1220,9 @@
     /**
      * Returns a synchronized collection backed by the given collection.
      * <p>
-     * You must manually synchronize on the returned buffer's iterator to 
+     * You must manually synchronize on the returned buffer's iterator to
      * avoid non-deterministic behavior:
-     *  
+     *
      * <pre>
      * Collection c = CollectionUtils.synchronizedCollection(myCollection);
      * synchronized (c) {
@@ -1139,14 +1232,14 @@
      *     }
      * }
      * </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 Collection synchronizedCollection(Collection collection) {
+    public static <C> Collection<C> synchronizedCollection(Collection<C> collection) {
         return SynchronizedCollection.decorate(collection);
     }
 
@@ -1159,7 +1252,7 @@
      * @return an unmodifiable collection backed by the given collection
      * @throws IllegalArgumentException  if the collection is null
      */
-    public static Collection unmodifiableCollection(Collection collection) {
+    public static <C> Collection<C> unmodifiableCollection(Collection<C> collection) {
         return UnmodifiableCollection.decorate(collection);
     }
 
@@ -1173,31 +1266,19 @@
      *
      * @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 Collection predicatedCollection(Collection collection, Predicate predicate) {
+    public static <C> Collection<C> predicatedCollection(Collection<C> collection, Predicate<? super C> predicate) {
         return PredicatedCollection.decorate(collection, predicate);
     }
 
     /**
-     * Returns a typed collection backed by the given collection.
-     * <p>
-     * Only objects of the specified type can be added to the collection.
-     * 
-     * @param collection  the collection to limit to a specific type, must not be null
-     * @param type  the type of objects which may be added to the collection
-     * @return a typed collection backed by the specified collection
-     */
-    public static Collection typedCollection(Collection collection, Class type) {
-        return TypedCollection.decorate(collection, type);
-    }
-    
-    /**
      * 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 
+     * Collection. It is important not to use the original collection after invoking this
      * method, as it is a backdoor for adding untransformed objects.
      * <p>
      * Existing entries in the specified collection will not be transformed.
@@ -1208,8 +1289,21 @@
      * @return a transformed collection backed by the given collection
      * @throws IllegalArgumentException  if the Collection or Transformer is null
      */
-    public static Collection transformedCollection(Collection collection, Transformer transformer) {
+    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();
+    }
 }



Mime
View raw message