I've a variety of collection utility classes that I've used on a various
projects that I'd like to contribute to the collections project.

I've attached all the source code for the new classes in the
org.apache.commons.collections package with ASF licences attached as a JAR.
Its all ready to just unjar into the source directory of the collections
project. I haven't included JUnit test scripts for this code yet, I thought
I'd wait for approval of the patch first before porting those.

The code consists of new classes together with a patch to CollectionUtils to
add a number of extra helper methods. I've attached a seperate patchfile.txt
which contains the new methods on CollectionUtils.

Probably the easiest way to browse the code is to unjar the patch.jar into
the source directory and build the javadoc and browse that. I'll try give a
brief overview of the classes here.


Adapters
======
ArrayIterator: like ArrayEnumeration for the Iterator interface

EnumerationIterator & IteratorEnumeration:  allow both Iterator and
Enumeration objects to be adapted to each other. Trivial stuff but I've
found this useful.

Map implementations
==============
BeanMap: properties of the bean appear as values. so map.get( "name" ) =
bean.getName();

LRUMap: implements an LRU caching mechanism, useful for fixed size caches

SoftRefHashMap: implements a HashMap using SoftReferences such that the JVM
can garbage collect values if memory gets low. Again useful for caches.

Various
=====
MapUtils: provides a number of typesafe getter methods to extract specific
types from Maps. Again trivial but helpful. There's also some printing
methods to dump nested Map objects to streams for debugging purposes.

SynchronizedQueue: I've used this class alot in multi-threaded environments
for implementing blocking producer / consumer queues.

Closures
======
After reading a bit about Closures in languages such as Smalltalk and some
JavaWorld article a year or so ago, I implemented a simple "closures"
implementation using Java 2 collections.

Firstly there are 3 simple interfaces:-

public interface Predicate {

    /** @return true if the input object matches this predicate, else
returns false
      */
    public boolean evaluate(Object input);
}

public interface Closure {

    /** Performs some operation on the input object
      */
    public void execute(Object input);
}

public interface Transformer {

    /** Transforms the input object (leaving it unchanged) into some output
object.
      * @return the transformation of the input object to the output object
      */
    public Object transform(Object input);
}

All of the above I've found quite useful in their own right doing other
code.

CollectionUtils has a variety of closure style methods (as well as other
useful Collection based methods) most of which use one or more of the above
interfaces.
I'll list a few example methods here:-

    Collection collection = ...;

    Predicate predicate = new Predicate() {
        public boolean evaluate(Object object) {
            if ( object instanceof String ) {
                String s = (String) object;
                return s.startsWith( "foo" );
            }
            return false;
        }
    };

    Closure closure = new Closure() {
        public void execute(Object object) {
            // do something
        }
    };

    Transformer transformer = new Transformer () {
        public Object transform(Object object) {
            return "something: " + object;
        }
    };

    // find first element matching predicate
    Object value = CollectionUtils.find( collection, predicate );

    // find all elements matching predicate
    Collection subset = CollectionUtils.select( collection, predicate );

    // perform a closure on the objects in some collection
    CollectionUtils.forAllDo( collection, closure );

    // return a collection of transformed objects
    Collection newColl = CollectionUtils.collect( collection, transformer );


Plus a few additional iterators which use these interfaces such as

    FilterIterator which takes an Iterator and a Predicate to perform
filtered iteration
    TransformIterator which takes an Iterator and a Transformer to provide a
transformed iteration set


If some or all of these classes get accepted, I'd be happy to check them
into CVS and create JUnit test cases for them all.

Thoughts?

James

patch.jar

Index: CollectionUtils.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons/collections/src/java/org/apache/commons/collections/CollectionUtils.java,v
retrieving revision 1.1
diff -b -u -r1.1 CollectionUtils.java
--- CollectionUtils.java        2001/04/24 18:48:36     1.1
+++ CollectionUtils.java        2001/04/29 11:14:32
@@ -63,6 +63,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -74,6 +75,7 @@
  * A set of {@link Collection} related utility methods.
  *
  * @author Rodney Waldhoff
+ * @author <a href="mailto:[EMAIL PROTECTED]";>James Strachan</a>
  *
  * @version $Id: CollectionUtils.java,v 1.1 2001/04/24 18:48:36 rwaldhoff Exp $
  */
@@ -293,4 +295,128 @@
         }
         return 0;
     }
+    
+    
+    /** Finds the first element in the given collection which matches the given 
+predicate
+      *
+      * @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 ) {
+        if ( collection != null && predicate != null ) {            
+            for ( Iterator iter = collection.iterator(); iter.hasNext(); ) {
+                Object item = iter.next();
+                if ( predicate.evaluate( item ) ) {
+                    return item;
+                }
+            }
+        }
+        return null;
+    }
+    
+    /** Executes the given closure on each element in the colleciton
+      */
+    public static void forAllDo( Collection collection, Closure closure) {
+        if ( collection != null ) {
+            for ( Iterator iter = collection.iterator(); iter.hasNext(); ) {
+                Object element = iter.next();
+                closure.execute( element );
+            }
+        }
+    }
+
+    /** Selects all elements from inputCollection which match the given predicate
+      * into an output collection
+      */
+    public static Collection select( Collection inputCollection, Predicate predicate 
+) {
+        ArrayList answer = new ArrayList( inputCollection.size() );
+        select( inputCollection, predicate, answer );
+        return answer;
+    }
+    
+    /** Selects all elements from inputCollection which match the given predicate
+      * and adds them to outputCollection
+      *
+      * @return the outputCollection
+      */
+    public static Collection select( Collection inputCollection, Predicate predicate, 
+Collection outputCollection ) {
+        if ( inputCollection != null && predicate != null ) {            
+            for ( Iterator iter = inputCollection.iterator(); iter.hasNext(); ) {
+                Object item = iter.next();
+                if ( predicate.evaluate( item ) ) {
+                    outputCollection.add( item );
+                }
+            }
+        }
+        return outputCollection;
+    }
+    
+    /** Transforms all elements from inputCollection with the given transformer 
+      * and adds them to the outputCollection
+      */
+    public static Collection collect( Collection inputCollection, Transformer 
+transformer ) {
+        ArrayList answer = new ArrayList( inputCollection.size() );
+        collect( inputCollection, transformer, answer );
+        return answer;
+    }
+    
+    /** Transforms all elements from the inputIterator  with the given transformer 
+      * and adds them to the outputCollection
+      */
+    public static Collection collect( Iterator inputIterator, Transformer transformer 
+) {
+        ArrayList answer = new ArrayList();
+        collect( inputIterator, transformer, answer );
+        return answer;
+    }
+    
+    /** Transforms all elements from inputCollection with the given transformer 
+      * and adds them to the outputCollection
+      *
+      * @return the outputCollection
+      */
+    public static Collection collect( Collection inputCollection, final Transformer 
+transformer, final Collection outputCollection ) {
+        if ( inputCollection != null ) {
+            return collect( inputCollection.iterator(), transformer, outputCollection 
+);
+        }
+        return outputCollection;
+    }
+
+    /** Transforms all elements from the inputIterator with the given transformer 
+      * and adds them to the outputCollection
+      *
+      * @return the outputCollection
+      */
+    public static Collection collect( Iterator inputIterator, final Transformer 
+transformer, final Collection outputCollection ) {
+        if ( inputIterator != null && transformer != null ) {            
+            while ( inputIterator.hasNext() ) {
+                Object item = inputIterator.next();
+                Object value = transformer.transform( item );
+                outputCollection.add( value );
+            }
+        }
+        return outputCollection;
+    }
+
+    /** Adds all elements in the iteration to the given collection 
+      */
+    public static void addAll( Collection collection, Iterator iterator ) {
+        while ( iterator.hasNext() ) {
+            collection.add( iterator.next() );
+        }
+    }
+    
+    /** Adds all elements in the enumeration to the given collection 
+      */
+    public static void addAll( Collection collection, Enumeration enumeration ) {
+        while ( enumeration.hasMoreElements() ) {
+            collection.add( enumeration.nextElement() );
+        }
+    }    
+    
+    /** Adds all elements in the array to the given collection 
+      */
+    public static void addAll( Collection collection, Object[] elements ) {
+        for ( int i = 0, size = elements.length; i < size; i++ ) {
+            collection.add( elements[i] );
+        }
+    }    
 }

Reply via email to