A Groovy Closure is like a "code block" or a method pointer. It is a piece of code that is defined and then executed at a later point. It has some special properties like implicit variables, support for currying and support for free variables (which we'll see later on). We'll ignore the nitty gritty details for now (see the formal definition if you want those) and look at some simple examples.
def clos = { println "hello!" }
println "Executing the Closure:"
clos() //prints "hello!"
|
Note that in the above example, "hello!" is printed when the Closure is called, not when it is defined.
Closure parameters are listed before the -> token, like so:
def printSum = { a, b -> print a+b }
printSum( 5, 7 ) //prints "12"
|
The -> token is optional and may be omitted if your Closure definition takes fewer than two parameters.
A Closure without -> , i.e. {} , is a Closure with one argument that is implicitly named as 'it'. (see below for details) In some cases, you need to construct a Closure with zero arguments, e.g. using GString for templating, defining EMC Property etc. You have to explicity define your Closure as { -> } instead of just { }
You can also use varargs as parameters, refer to the Formal Guide for details. A JavaScript-style dynamic args could be simulated, refer to the Informal Guide.
Closures may refer to variables not listed in their parameter list. Such variables are referred to as "free" variables. They are "bound" to variables within the scope where they are defined:
def myConst = 5
def incByConst = { num -> num + myConst }
println incByConst(10) // => 15
|
Or another example:
def localMethod() {
def localVariable = new java.util.Date()
return { println localVariable }
}
def clos = localMethod()
println "Executing the Closure:"
clos() //prints the date when "localVariable" was defined
|
Within a Groovy Closure, several variables are defined that have special meaning:
If you have a Closure that takes a single argument, you may omit the parameter definition of the Closure, like so:
def clos = { print it }
clos( "hi there" ) //prints "hi there"
|
this : as in Java, this refers to the instance of the enclosing class where a Closure is defined
owner : the enclosing object (this or a surrounding Closure)
delegate : by default the same as owner, but changeable for example in a builder or ExpandoMetaClass
Example:
class Class1 {
def closure = {
println this.class.name
println delegate.class.name
def nestedClos = {
println owner.class.name
}
nestedClos()
}
}
def clos = new Class1().closure
clos.delegate = this
clos()
/* prints:
Class1
Script1
Class1$_closure1 */
|
When a method takes a Closure as the last parameter, you can define the Closure inline, like so:
def list = ['a','b','c','d']
def newList = []
list.collect( newList ) {
it.toUpperCase()
}
println newList // ["A", "B", "C", "D"]
|
In the above example, the collect method accepts a List and a Closure argument. The same could be accomplished like so (although it is more verbose):
def list = ['a','b','c','d']
def newList = []
def clos = { it.toUpperCase() }
list.collect( newList, clos )
assert newList == ["A", "B", "C", "D"]
|
Groovy extends java.lang.Object and many of the Collection and Map classes with a number of methods that accept Closures as arguments. See GDK Extensions to Object for practical uses of Groovy's Closures.
See Also: