Groovy Functional Programming - Closures
From functions to closures
Consider the following function.
def greet() {
println "Hello"
}
You can invoke the greet
function in the following way
greet() // prints "Hello"
Unlike variables/ values, one can neither pass a function as an argument to another function nor return a function from another function. This means functions are not treated as types and thus second class citizens. However one can express the same functionality using closure
constructs.
def greet = {
println "Hello"
}
A closure is a block of code wrapped in a pair of {}
. In the above example, we have assigned the code block to the variable greet
. Invoking this piece of code is very similar to calling a function.
greet() // prints "Hello"
Hence one can use Groovy closures for programming in functional style.
Closure Arguments
By default, closures accept a single argument and assumes the name it
def greet = {
println "Hello $it"
}
greet('Kumar') // Hello Kumar
greet() // Hello null
The above code example illustrates that the closure we defined earlier indeed accepts a single argument and we can access that argument using it
. When we invoke the closure without passing an argument it
assumes null
.
While Groovy provides a convenient name for the default argument, by defining the parameter name explicitly, a developer can convey the intention better and readability of the code will improve. Groovy allows us to do that
def greet = { friend ->
println "Hello $friend"
}
greet('Kumar') // Hello Kumar
greet() // Hello null
If you wish to specify the type for the parameter, you could change the code as follows.
def greet = { String friend ->
println "Hello $friend"
}
Default name or explicit name?
My preference goes like this - If the closure body contains more than a single line of code, I name the parameter instead of using the defaultit
.
Multiple Arguments
The following code example shows how we can define a closure with multiple arguments.
def greetWithMessage = { friend, message ->
println "Hey $friend, $message"
}
greetWithMessage('Kumar', 'Good morning') // Hey Kumar, Good morning
Closure with zero arguments
Interestingly, if you want to define a closure that doesn't accept any arguments, use ->
after the open brace {
as follows.
def greet = { ->
println "Hello"
}
You may want to take a look at slides from my FunctionalConf talk for more examples.