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 default it.

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.

Show Comments