Groovy Closure Example
In this example I’ll explain closures in Groovy.
According to Sabesta’s nice book Concepts of Programming Languages, defining a closure is a simple matter: “a closure is a subprogram and the referencing environment where it was defined.” But explaining it is not that simple. Sabesta explains the closure as a subprogram that can be assigned to a variable or passed to another subprogram so that it can be called anywhere. So far this may not be astonishing. But what is interesting is the fact that assigned or passed subprogram should be able to access all of the variables in its referencing environment. So we can call a closure an anonymous function with a storage.
Groovy as many other programming languages with some functional structures provides closures.
And now the real question comes: why do I need such an awkward structure? Of course to write shorter and more modular programs. Let’s imagine you have several methods that share only a few lines. Most of the time you factor out those shared lines into another method so that your original methods would make a call to this new method. That is modularising the methods. You can think of a closure as the function factored out in this example with one huge difference: Instead of calling the closure in your original methods, you are passing the closure back to those methods as if it were a variable.
That’s why in languages that support closures, they are called “first-class objects”. On the other hand the functions that receive or return (or both) closures are called higher-order function.
Instead of delving into the theoretical details of the concept, let’s focus on how Groovy provides closures as one of its main structures. According to Groovy’s standard documentation a closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. That means as we can pass a variable around the program we can pass closures back and forth in the program.
1. Defining a Closure in Groovy
In Groovy you can define a closure as a block between two curly brackets “{ [closureParameters -> ] statements }
“. In this format [closureParameters->]
is an optional comma-delimited list of parameters, and statements are 0 or more Groovy statements. The parameters look similar to a method parameter list, and these parameters may be typed or untyped. When a parameter list is specified, the “->
” character is required to separate the parameters from the closure body.
Here are some example closure definitions and what they mean:
{ "hello" } // A closure that receives no argument but returns a String object. { it -> println it } // A closure that prints what is passed. "it" is the explicit // reference to the parameter passed to the closure. { println it } // A closure that prints what is passed. "it" is the implicit // reference to the parameter passed. // You can omit the parameter if only one parameter is passed. { name -> println name } // Same closure with different parameter name. {double x, double y -> println Math.pow(x, y)} // A closure that receives two parameters // and prints the value of the first // parameter raised to the power of the second one.
As you notice, a closure may have zero or more arguments but does not have any name.
In Groovy a closure must be either assigned to a variable or attached to a method. So closures defined above should be used as explained below.
2. Using Closures in Groovy
A closure is an instance of the groovy.lang.Closure
class. So you can treat it as an object and call for example call()
method on it. You can also use instanceof
operator check to see if it is instance of the Closure. For example:
def closure1 = { 10 } // Defining a closure of value "10" println(closure1.call()) // Will print out "10" assert closure1() == 10 // Assertion holds true def b = closure instanceof Closure println(b) // Prints true
def closure2 = { print 10 } // Defining a closure to print "10" closure2.call() // Will print out "10"
def closure3 = { println it } // Defining a closure to print the passed parameter closure3.call(5) // Will print out "5" closure3.call() ; // Will print out "null" { it -> println it }.call(5) // Will print out "5"
One of the places where closures are frequently used are collections. For example in Groovy following code snippet prints out all of the elements in the list:
def List numbers = [1, 2, 3, 5, 8, 13, 21] for(n in numbers) print n
But using closures you can do the same thing in a more elegant way:
def List numbers = [1, 2, 3, 5, 8, 13, 21] numbers.each {print it + ', '}
Groovy uses Java’s collections but enhances their API with several methods that receive a Closure object. For example methods each() or find() may receive a Closure object. Here are some examples of using closure with collections:
def List numbers = [1, 2, 3, 5, 8, 13, 21] numbers.each {print it + ', '} // Prints 1, 2, 3, 5, 8, 13, 21, def found = numbers.find {it % 2 == 0} println(found) // Prints 2 List foundNumbers = numbers.findAll {it % 2 == 0} println(foundNumbers) // Prints [2, 8]
You can pass a closure to a method. Following example shows how to do it:
def static callAMethod(){ def aClosure = { it -> println it } aMethod(10, aClosure); aMethod(10, { it -> println it }) aMethod(10) { it -> println it } aMethod(23, aClosure); } def static aMethod(int i, closure){ println"Here is the output of passed closure:" closure(i) }
As a last example let’s try to understand how closures help us make our code more modular. Think about following class with three methods:
EvenNumberCalculations.groovy
class EvenNumberCalculations { static main(args) { def obj = new EvenNumberCalculations() obj.printEvenNumbers(10) def result = obj.calculateSumOfEvenNumbers(10); println('Total: ' + result) result = obj.calculateProductOfEvenNumbers(10); println('Product: ' + result) result = obj.calculateSquareOfEvenNumbers(10); println('Squared: ' + result) } def printEvenNumbers(int n){ for(int i = 2; i <= n; i += 2) { println(i) } } int calculateSumOfEvenNumbers(int n){ def sum = 0; for(int i = 2; i <= n; i += 2) { sum += i } return sum; } int calculateProductOfEvenNumbers(int n){ def product = 1; for(int i = 2; i <= n; i += 2) { product *= i } return product; } int[] calculateSquareOfEvenNumbers(int n){ def squared = [] for(int i = 2; i <= n; i += 2) { squared << i ** 2 } return squared; } }
How can we utilise closures here? We can factor out what is done in for loops of these methods and express them as closures. So we would re-write the same class using closures:
EvenNumberCalculationsWithClosure.groovy
class EvenNumberCalculationsWithClosure { static main(args) { def obj = new EvenNumberCalculationsWithClosure() obj.pickEvenNumbers(10, { println it }) def total = 0 obj.pickEvenNumbers(10) { total += it } println('Total: ' + total) def product = 1 obj.pickEvenNumbers(10) { product *= it } println('Product: ' + product) def squared = [] obj.pickEvenNumbers(10) { squared << it ** 2 } println('Squared: ' + squared) } def pickEvenNumbers(n, block) { for(int i = 2; i <= n; i += 2) { block(i) } } }
3. Closing Thoughts
Closures are very handy tools in Groovy. They help you make your code more concise and modular. But they are not alternatives to regular functions. You will notice that useful closures would start emerging during refactoring.
Although closures are the derivatives of lambda expressions and Java SE 8 started to support them, closures and lambda expressions are different structures and Java does not support closures yet. For more info regarding their differences you can have a look here.
4. Download The Eclipse Project
This is an example of closure in Groovy.
You can download the full source code of this example as an Eclipse project here: GroovyClosureExample
Please try {“xx”}() alone and {“xxxx”}() alone ; each works fine ; and then please try {“xx”}() and next line {“xxxx”}() in GroovyConsole.
I get:
groovy> {“xx”}()
groovy> {“xxxx”}()
Exception thrown …