Wednesday, February 23rd, 2011

“Stealth” Groovy Methods

Groovy has a number of simple and useful methods that are almost impossible to find by a web search. Try as you wish, googling for any, find, or count just gets you a giant haystack hiding the proverbial buried needle. And... hey, what was the name of that method that lets you insert a value into an iteration, kind of?

This post is about those Groovy methods that are all over the place, and yet hard to find. I wrote it as a reminder to myself.

First of all, the key to many "stealth" methods is the class org.codehaus.groovy.runtime.DefaultGroovyMethods. It's in the API docs (not to be confused with the GAPI or Groovy-JDK docs). It's a treasure trove of Groovy goodies. Make sure you browse the documentation of this class now and then. You will almost certainly be reminded of useful stuff or learn something new. Just keep in mind that there is syntactic sugar for some of them. For instance, the getAt method can be invoked with the "[]" syntax. Invoking by name is completely legal, but not as elegant.

Unfortunately there are missing pieces in the documentation. For instance, if a method takes a closure argument, the arguments of that closure may be undocumented.

To spare you haystack time, let's dive into some code.

inject & co
The inject method is useful to compute a single value from a collection or an array. The argument is passed ("injected") into the first iteration. The value returned by an iteration is passed into the subsequent iteration, or returned as the result at the end of iteration.

The second argument is a closure that takes the following arguments,

  1. The injected value
  2. The iteration item

The following example begins with an anti-pattern to avoid, followed by the Groovy way. The Groovy way happens to coincide with functional programming style.

GROOVY:

  1. def mylist = [1, 2, 3, 4, 5]
  2.  
  3. // Anti-pattern to avoid
  4. int sumSquares = 0
  5. mylist.each{item -> sumSquares += item*item}
  6. assert sumSquares == 55
  7.  
  8. // inject: the Groovy way
  9. sumSquares = mylist.inject(0) {sum, item ->
  10.     sum + item*item
  11. }
  12. assert sumSquares == 55
  13.  
  14. // join: a special case
  15. assert mylist.join(':') == '1:2:3:4:5'
  16.  
  17. // find: single out an item
  18. // This example finds the first even number
  19. assert mylist.find {it % 2 == 0} == 2
  20.  
  21. // find: may return nothing (i.e. null)
  22. assert mylist.find {it <0} == null

The join method is included in the example above. It is almost a special case of inject. It appends the toString images of the iteration values.

The find method is also included. It doesn't do any aggregation. It just finds an element matching a condition, or returns null. Groovy Truth applies, as the next example shows.

GROOVY:

  1. // find: uses Groovy Truth
  2. assert ['', 0, null, false, 'hi', 17].find {it} == 'hi'

Learn the inject method and its cousins, join and find. They make your code more readable, more functional, and hence more robust.

Comments are closed.