My Blog has moved to Github Pages

Saturday 2 October 2010

Filtering Java Collections

OK, its my first ever blog post, so no laughing - gotta start somewhere, right?  It doesn't help that the cat is tap-dancing on my keyboard at every opportunity.

Anyways, I recently made a couple of handy utility methods and classes for filtering and transforming java.util.List's (well, Iterable's actually), using a more functional approach, which I thought I'd describe.  For a first-post I thought i'd start with filtering. (I know, I know, Google-collections / Guava ... hey I like programming for programming's sake ok?).

The basic problem is: you have a List of Objects of some type, and you want to create a new List containing a subset of the original, where some objects are removed based on some properties of those Objects.  To make the example concrete lets say we have a list of Strings (List<String>) and we want to remove any String with length less than 3 characters.  The obvious way to do it is:



Short and simple, but not particularly pretty, readable or re-usable.  Lets not forget that here the predicate or "test" is simple - as the complexity of the predicate grows, so the readability of this implementation declines.  A natural next step with a more complex predicate would, of course, be to factor the predicate out into a separate method. 

One thing that certainly doesn't feel right is that the predicate is actually expressed as an inverse of the intended behaviour - it basically says "if the string has at least 3 characters, keep it".

Anyway, after filtering a few lists with code similar to this, I decided to factor it out into something that's a little more re-usable, makes it easier to express the intent, and thus makes the code more readable.  First, lets look at what the same operation would look like using the utility code, then we'll get to the utility itself:



Now that's a little more wordy, largely because of Java's lack of closure's, but that's a topic for another post :).  What I do like about it is that the intent is expressed more clearly - "filter", "remove", aString.length() < 3.

We could make it clearer by writing the Filter implementation as a separate top-level (or nested) class, instead of an anonymous one:



Alternatively we can achieve similar clarity with an anonymous inner class by factoring out the creation of that class into a separate method:



Here the slightly unconventional method name "stringsShorterThan" helps readability in the calling code.

I put the utility code for this into a little class where we were already gathering some other general utility methods, innovatively called "Util".  It looks something like this:



Unsurprisingly that's just the code we started with, factored out into a utility method that ever-after lets you provide just the predicate for removal, wrapped in a little boiler plate.  If the predicate is complex, or frequently needed, you can factor it out into a top-level class, create a test-case for it, and benefit from re-use.

No comments:

Post a Comment