Closures
Prerequisites: Methods
A closure is a block of code you can store in a variable, pass to a
method, and call later. Closures are the heart of idiomatic Groovy —
you've already used them with each and times.
def square = { x -> x * x }
def greet = { name, greeting = 'Hello' -> "$greeting, $name!" }
def shout = { it.toUpperCase() + '!' } // "it": the single implicit parameter
def now = { -> 'no parameters' }
println square(4)
println square.call(5)
println greet('Ada')
println greet('Linus', 'Hi')
println shout('hey')
println now()
16
25
Hello, Ada!
Hi, Linus!
HEY!
no parameters
- Parameters go before
->; the body comes after. - With no
->, the closure has one implicit parameter namedit. { -> ... }declares a closure that takes no parameters.- The last expression is the return value.
Passing closures to methods
def repeat(int times, Closure action) {
for (i in 1..times) action(i)
}
repeat(3) { n -> println "call number $n" }
def numbers = [1, 2, 3, 4, 5]
println numbers.collect { it * 10 }
println numbers.findAll { it % 2 == 1 }
println numbers.find { it > 3 }
call number 1
call number 2
call number 3
[10, 20, 30, 40, 50]
[1, 3, 5]
4
When the last argument of a method is a closure, you can write it
after the parentheses — repeat(3) { ... } — or drop the parentheses
completely if it's the only argument: numbers.each { ... }. That's
what makes Groovy code (and Gradle and Jenkins files) read like a
language of its own.
Closures capture variables
def counter = 0
def increment = { counter++ }
increment()
increment()
increment()
println counter
def makeMultiplier(factor) {
return { value -> value * factor }
}
def triple = makeMultiplier(3)
println triple(7)
3
21
A closure can read and change variables from the scope where it was
created, even after that scope has finished — triple still knows
factor is 3. That's where the name "closure" comes from.
Method references
def words = ['groovy', 'java', 'kotlin']
println words.collect(String::toUpperCase)
println words.collect { it.capitalize() }
[GROOVY, JAVA, KOTLIN]
[Groovy, Java, Kotlin]
Java-style method references (Class::method) work in Groovy 3 and
later. Level 2 goes much deeper: currying, composition, delegates, and
how closures power builders and DSLs.