One of the new and different features of Groovy is Closures. Closures are a very powerful feature of Groovy, and one of the must deeply used, so they must definitely be understood to take full advantage of the language.
Sometimes people have trouble understanding closures, because there is no such construct in Java.However they are not really hard to understand, taking into account that Groovy is a 100% Object Oriented Language, and that it compiles to normal Java classes.
I will explain the basics of closures making a comparison between Code using closures, and showing (rather roughly) how this would translate into Java.
First a fast introduction.
A simple definition to Closures, is to say that they are language constructs that encapsulate behaviour, as functions, and can be referenced and passed around the code. Expressing it in Java terms they are like a Method without an associated class (We'll see later that this is not true) that can be referenced and passed around as an object.
The construct of a Closure in Groovy is like this:
{}
Yes, that's it, an open curly brace and the closing curly brace. That is the most simple closure, that actually doesn't do anything.
Closures can take parameters, like this {arg1->}. That closure receives one parameter and doesn't do anything.
A closure can for example return the double of it's argument {arg -> arg*2}
You pass a closure to a method as the last argument of the method without parentheses. For example we can have a method somewhere that receives a closure: def methodFoo(closureArg). And it can be called like
methodFoo{arg ->}
From this point, for the purpose of the explanation, we will use the each method on a Groovy List, which receives a closure as parameter and passes every element of the list to this closure.
Let's suppose we want to print de double of each element of a integer list.
[1,2,3,4].each{element -> print element*2}
That's it we printed the double of each element. To achieve the same in Java, and supposing that there exists an each method on java.util.List and that we already built our list with the four elements, it would be something like:
interface MethodObject{
void execute(Integer element); }
list.each(new MethodObject(){
public void execute(Integer element){
System.out.println(element * 2) }
})
As we can see, closures are a really nice way of implementing callbacks at the language level.
In the first case the each method will be something like:
each(closure){
for(element in this){
closure.call(element) }
}
the second case will look almost the same:
each(MethodObject callback){
for(Integer element : this){
callback.execute(element)
}
}
Closures in groovy are actually objects of type groovy.lang.Closure. So the constructor def a = {arg ->} actually creates an object of type Closure, which as we can see have the method call.
A common source of confusion for closures is the scope of the variables around the closure. For me the best way to understand how this works is to think that at the time of the closure declaration, al visible variables are passed to the closure. For example, taking the previous example and this time multipliying the element by a number taken for the outer scope, we get the following.
def multiplier = 3
[1,2,3,4].each{element -> print element*multiplier}
We can see that the closure can access the reference multiplier and use it.
As objects, i think that what happens is something like the following(Of course this is not at all the way it is implemented, it's just a way to understand that the closures have access to the local variables in the scope where they there are declared):
Integer multiplier=3;
interface MethodObject{
void execute(Integer element);
}
class MethodObjectImpl implements MethodObject{
private Integer multiplier;
public MethodObjectImpl(Integer multiplier){
this.multiplier=multiplier;
}
public void execute(Integer element){
System.out.println(element*multiplier)
}
}
list.each(new MethodObjectImpl(multiplier));
As we can see, the local variable "multiplier" would be passed to the declaration of the closure object, so that it "remembers" the variable when it is executed.
So, i think that the most important thing to remember about closures is that they are a very convenient way of expressing callbacks, that they are objects (even although syntactically they don't look like it), and that they remember the variables on their out local scope.
2 comments:
No such construct in Java? Never heard of annonymous inner classes?
It always amazes me that people who claim to know about programming aren't able to see that AICs and Closures are one and the same thing.
But hey, they have different names, so obviously it's a tall order to expect that programmers are able to see the similarity...
Hi Annonymous, if you actually read the post, you would see that i know what an annonymous inner class is as i'm actually using them in the line
list.each(new MethodObject(){
public void execute(Integer element){
System.out.println(element * 2) }
})
So you have to read the post and not just pointing out negative stuff.... And not. they are not the same construct as a closure. But i leave it to you to think so...
Post a Comment