Definition and Invocation
A closure in Groovy is an anonymous code block enclosed in curly braces. It can be assigned to variables, passed as arguments, and invoked on demand.
def greet = { println 'Hello from Groovy' }
Invoke a closure using the call method or through direct parentheses syntax:
greet.call()
greet()
Parameter Handling
When a closure accepts no arguments, define an explicit empty parameter list with an arrow:
def noArgs = { -> println 'Running without parameters' }
noArgs()
For a single typed parameter, declare it before the arrow:
def welcome = { String user -> println "Welcome, ${user}" }
welcome('Developer')
Multiple parameters are separated by commas:
def configure = { String env, int port ->
println "Environment: ${env}, Port: ${port}"
}
def serverPort = 8080
configure('production', serverPort)
If parameters are omitted, Groovy provides an implicit argument named it:
def echo = { println "Received: ${it}" }
echo('message')
Declaring any parameter explicitly removes the implicit it. The closure body then relies solely on the named arguments.
Return Values
Every closure evaluates to the value of its last expression. When the final statement is a method call that yields nothing, or when the block is empty, the result is null:
def printer = { println "Value: ${it}" }
def outcome = printer('sample')
println outcome // null
Use an explicit return or simply let the final expression stand as the result:
def formatter = { return "Formatted: ${it}" }
def result = formatter('data')
println result
Iterating with Numeric Ranges
Closures integrate tightly with numeric types to provide concise iteration.
The upto method counts upward through a range, inclusive of both endpoints:
3.upto(8) { println it }
This pattern simplifies accumulation tasks:
def sum = 0
1.upto(100) { sum += it }
println sum
For downward iteration, use downto:
10.downto(4) { println it }
The times method repeats from zero up to, but not including, the given number:
5.times { println it }
It can also drive aggregate calculations:
def total = 0
11.times { total += it }
println total
When a closure is the final argument to a method, Groovy allows it to appear outside the parentheses:
// idiomatic
3.upto(7) { println it }
// valid but less common
3.upto(7, { println it })
Processing Strings and Collections
Closures serve as the primary mechanism for traversing and transforming strings.
def phrase = "Groovy 4.0 Release"
// Iterate over each character
phrase.each { println it }
// Locate the first digit
println phrase.find { it.isNumber() }
// Gather all digits
def numbers = phrase.findAll { it.isNumber() }
println numbers
// Check if any character satisfies a condition
println phrase.any { it.isNumber() }
// Verify that all characters satisfy a condition
println phrase.every { it.isNumber() }
// Transform each element and collect results
def transformed = phrase.collect { it.toUpperCase() }
println transformed
Note that find expects the closure to evaluate to a boolean for matching, while each returns the original collection (or string) after completion.