Wednesday, September 7, 2011

Guava: pidgin functional programming in Java

Google's guava library provides a few constructs that let us use functional style in Java. Personally, I enjoy the slightly more declarative style that results, and have a new game of eliminating loops. Unfortunately, it's Java. Attempting to do anything functionally is rather ugly. What do you think - worth it? or unreadable?

Before:
   public List getUsefulThings() {
       List usefulThings = newArrayList(); // this is also a use of Guava
       for(Thing t : listOfThings) {
          if (t.isUseful()) {
              usefulThings.add(t);
          }
       }
       return usefulThings;
   }


After:
   private static final Predicate THING_IS_USEFUL_PREDICATE = new Predicate() {
                 public boolean apply(Thing input) {
                       return input.isUseful();
                 }
      };

   public Iterable getUsefulThings() {
      return filter(listOfThings, THING_IS_USEFUL_PREDICATE);
   }


The goal is to make the code in getUsefulThings() state what the method is doing, rather than how it goes about it. "Look through this list and if something is useful, put it in the output" is a "how." "Filter this list on this predicate" is a "what."

I like to put the predicate in a static variable largely because it's hideous (thanks to Java syntax). The name of the predicate is more readable than the predicate itself.

There is one additional subtle advantage to the Guava method of returning useful things: the filtering doesn't happen until someone uses the output. The Iterable returned is lazy. If the caller only wants the first usefulThing:

      {
         Thing usefulThing = getUsefulThings().iterator().next();
         doSomething(usefulThing);
      }


... then with the Guava solution, the predicate checked against items in listOfThings only until the first useful Thing is found. The rest of listOfThings won't be processed at all. Lazy evaluation in Java!

Then again, this lazy evaluation can have an even more subtle effect: if the contents of listOfThings are modified after the call to getUsefulThings() but before that Iterable output is used, the Iterable will reflect the updated listOfThings. This goes to prove: mutability is evil.

No comments:

Post a Comment