Una de las cosas que distingue a Groovy de la mayoría de los lenguajes compilados es que se pueden crear funciones como si fueran objetos comunes. Es decir, se puede definir una porción de código y pasarla por parámetro como si fuera un string o un integer.
Los closures se encierran entre llaves, y se pueden asignar a variables como si fuera un objeto más. Por ejemplo, definamos una porción de código para calcular el cuadrado de un número:
cuadrado = {it * it}
Las llaves alrededor de "it * it" le dicen al compilador de Groovy que debe tratarse esta expresión como código. En el mundo del software esto es un "closure". En este caso, la referencia "it" se refiere a cualquier valor que se le pase a la función. Luego, esta función compilada es asignada a la variable "cuadrado", que es una variable más como las que vimos hasta ahora.
Entonces, podemos hacer lo siguiente:
println cuadrado(9)
Lo que imprime "81" por consola.
Esto no resulta muy útil hasta que nos damos cuenta que podemos pasar esta función "cuadrado" como un valor más. Hay varias funciones incorporadas a Groovy que reciben una función por parámetro. Un ejemplo es el método "collect" de los arrays. Por ejemplo:
[ 1, 2, 3, 4 ].collect(cuadrado)
Esta expresión crea un array con los valores 1,2,3 y 4, luego llama al método "collect", pasándole el closure que definimos antes. El método collect recorre cada elemento del array e invoca al closure con ese elemento, y luego pone el resultado en un nuevo array, resultando en:
[ 1, 4, 9, 16 ]
De manera predeterminada, los closures reciben 1 parámetro llamado "it", y también se pueden crear closures con varios parámetros. Por ejemplo:
imprimirMap = { clave, valor -> println clave + " es " + valor } [ "Zim" : "invasor", "Dib" : "humano", "Gaz" : "humana" ].each(imprimirMap)
Imprime por consola:
Zim es invasor
Dib es humano
Gaz es humana