Skip to main content

Groovy `each` - or why everything is a nail

With the aspiring groovyist there is a tendency to use each for everything. When coming from an imperative programming language you did all the heavy lifting with for, while, if, etc. so each gets adopted again for that style of programming. This at some point will end with the question: how to break out of an each. And the simple answer is: you can't (well, you shouldn').

In Groovy many things look like some basic instruction from the language, so each looks like some loop instruction from the Groovy language, right? [1,2,3].each{ println it }? Well actually each is just a method, that takes a clojure as param, for this list and Groovy allows you leave out parentheses in that case. Does this still look like something basic like for: [1,2,3].each({ println it }) ?

What does each do then? It runs a for loop and passes each element to your provided closure. Your return value is ignored. No break, no continue makes sense here. Actually return early in your closure provides continue behaviour. Also note, that the return value of the each method is the list itself.

So here are a few each anti-patterns:

each instead of a map:

// NO!
def results = []
[1,2,3].each{
        results << (it*it)
}
// YES!
def results = [1,3,4].collect{ it*it }

each instead of a filter:

// NO!
def results = []
[1,2,3].each{
        if (it>1) {
                results << it
        }
}
// YES!
def results = [1,2,3].findAll{ it>1 }

each to find first:

// NO, really NO!
def result
[1,2,3].each{
        if (it==2) {
                result = it
                break // does not work
        }
}
// YES!
def result = [1,2,3].find{ it==2 }

each instead of a reduce:

// NO!
def sum = 0
[1,2,3].each{
        sum += it
}
// YES
def sum = [1,2,3].sum()
// or as an actual reduce, if you prefer:
def sum = [1,2,3].inject(0) { r,it -> r += it }

So what when you really need the behaviour of for? Well it's not forbidden in groovy. Just use it, it's even faster than each.