Jon Aquino's Mental Garden

Engineering beautiful software jon aquino labs | personal blog

Thursday, February 03, 2005

An Implementation of Blocks In Java (or Introducing #collect and #select)

Smalltalkers are used to having #collect and #select to transform and filter their Collections (there are similar functions in LISP, Python, and Groovy, to name a few other languages). Well, now Javaheads can have their own #collect and #select methods.

The key to making #collect and #select work is having blocks. A block (or closure) is just a chunk of code that you can pass around. "But Java doesn't have real blocks", you say. Well, we can get a good approximation by making our own Block class. This will allow us to do things like the following:


CollectionUtil.collect(collection, new Block() {
public Object yield(Object item) {
return "Hello, " + item;
}
});


Basically, #collect lets you do something to each item of a collection, resulting in a new collection. #select lets you filter out items that do not mach a certain criterion:


CollectionUtil.select(collection, new Block() {
public Object yield(Object item) {
return Boolean.valueOf(((Thing)item).isCool());
}
}


And Blocks open up all sorts of possibilities in addition to #collect and #select. A block is just a chunk of code that you can pass around, like a function pointer in C. Sure, you can create your own specialized class or interface every time you want to allow one party to plug custom logic into another, but why not save yourself the trouble and use Blocks!

The cool thing about this implementation of Block is that it can take 0, 1, or 2 arguments -- whichever is required. Check it out:


public abstract class Block {
public Object yield() {
throw new UnsupportedOperationException();
}
public Object yield(Object arg) {
throw new UnsupportedOperationException();
}
public Object yield(Object arg1, Object arg2) {
throw new UnsupportedOperationException();
}
}


OK, now that we have the implementation of Block, we can take the next step and build #collect and #select methods (and others):


public class CollectionUtil {

public static Collection collect(Collection collection, Block block) {
ArrayList result = new ArrayList();
for (Iterator i = collection.iterator(); i.hasNext();) {
Object item = i.next();
result.add(block.yield(item));
}
return result;
}

public static Collection select(Collection collection, Block block) {
ArrayList result = new ArrayList();
for (Iterator i = collection.iterator(); i.hasNext();) {
Object item = i.next();
if (Boolean.TRUE.equals(block.yield(item))) {
result.add(item);
}
}
return result;
}
}


I'm sure others will come up with other good uses for Java Blocks!

4 Comments:

  • Good post, thanks. I'm really surprised that basic stuff like #collect, #select, #detect, etc. didn't make it into the java.util collections. To support my learning of J2SE 5 and to scratch an itch for such methods in a library as basic as collections, I created Jaggregate (http://sf.net/projects/jaggregate). Have a look at the source if you like!

    By Blogger Paul Holser, at 2/04/2005 11:51 AM  

  • Something along these lines is already implemented in Jakarta Commons Collections. Have a look at the Closure, Predicate, Transformer and Factory interfaces.

    Marius

    By Anonymous Anonymous, at 2/04/2005 12:00 PM  

  • Here is an excellent write up of using Blocks in Java: http://c2.com/cgi/wiki?BlocksInJava

    By Anonymous Anonymous, at 2/04/2005 4:31 PM  

  • Thanks, all, for the pointers to some very interesting reading.

    By Blogger Jonathan, at 2/04/2005 7:00 PM  

Post a Comment

<< Home