O que é uma closure?
Se há um ponto em Groovy que devemos nos aprofundar, este tópico consiste na descrição das closures (aliás, seriam “as closures” ou “os closures”?). Para aqueles que programam em linguagens que não oferecem este recurso, a seguinte metáfora descreve bem o que vêm a ser esta criatura:
Uma closure por sua vez consiste em um tipo diferente de variável. Seguindo a metáfora, nosso envelope conteria não uma informação, mas sim um conjunto de instruções, resumindo: código executável.
Como vocês perceberão daqui para frente: closures consistem em um daqueles recursos que, uma vez aprendido, ficamos impressionados com o fato de havermos conseguido programar tanto tempo sem utilizá-lo.
Como declarar uma closure
Como mencionado, uma closure consiste em mais um tipo de variável e, como tal, é declarado como uma variável, tal como no exemplo abaixo:
class ClasseBoba { // bla bla bla pra cima def closure = { println "Sou uma closure" } // bla bla bla pra baixo }
Como pode ser percebido, uma closure é definida quase que exatamente qualquer variável que conhecemos. A única diferença está na sintaxe. Ao lado direito da declaração, ao invés de incluirmos um valor, estamos incluindo um bloco de código executável. No caso, a closure ao ser invocada irá imprimir no console o texto “Sou uma closure”
Closures, assim como qualquer método, também possuem parametros. Caso nenhum parametro seja declarado (como no exemplo acima), estará disponível no bloco de código da closure uma variável implícita chamada it. Podemos portanto incrementar o exemplo tal como farei abaixo:
class ClasseBoba { // bla bla bla pra cima def closure = { println "Sou uma closure que recebeu como parâmetro o valor de ${it}" } // bla bla bla pra baixo }
Caso nenhum parâmetro seja passado para a closure, ela irá imprimir algo como
Sou uma closure que recebeu como parâmetro o valor de NULL.
Já o código abaixo, imprimiria de outra maneira:
def instancia = new ClasseBoba() instancia.closure("qualquer coisa") // Será impresso aqui exatamente //"Sou uma closure que recebeu como parâmetro o valor qualquer coisa"
Óbviamente, uma closure pode receber também mais de um parâmetro, tal como exposto no exemplo abaixo:
def soma = {a, b -> a + b}
Como pode ser visto no exemplo: se quisermos declarar os parâmetros de uma closure, estes estarão declarados no início do bloco. Finalizada a declaração dos atributos (você pode definir os tipos dos parâmetros se quiser também), segue a sequencia de caracteres “->”, que indica o início do bloco de código em questão.
No caso deste exemplo, criamos uma closure que faz a soma de duas variáveis.
Também é possível modificar o nome do parâmetro de uma closure, tal como no exemplo abaixo:
def closureBoba = {parametro -> println """Como pode ser visto, o parametro único não precisa se chamar it. Na realidade, pode ter o nome que você quiser. A propósito, recebi o valor de ${parametro}""" }
Como referenciar uma closure
Tal como mencionei no início, uma closure nada mais é do que uma variável. Na realidade, trata-se de uma instância da classe groovy.lang.Closure. Sendo assim, você a referencia da mesma maneira que faria com qualquer atributo/variável convencional, tal como no exemplo abaixo:
class Classe1 { def closureClasse1 } class Classe2 { def closureClasse2 } def closure = { println "Sou uma closure bem promíscua" } Classe1 classe1 = new Classe1() Classe2 classe2 = new Classe2() classe1.closure = closure classe2.closure = classe1.closure
O exemplo faz o seguinte: primeiro define duas classes (Classe1 e Classe2) e, em seguida, implementa uma closure bem simples.
Instanciadas tanto classe1 quanto classe2, primeiro definimos que a closure de classe1 será closure. Em seguida, definimos que a closure de classe2 será a mesma closure de classe1.
Perceberam que bacana? Com closures, podemos mudar o comportamento de nossas classes de uma maneira incrívelmente simples!
Como executar uma closure
A execução de uma closure é exatamente igual a execução de qualquer outro método Groovy, tal como pode ser visto no exemplo abaixo:
def soma = {a, b -> a + b} def closureSimples = {"Sou simples demais"} def closureOla = {"Olá ${it}"} soma(3, 4) // imprimirá 7 closureSimples() // imprime "Sou simples demais" closureOla("Kico") // imprime "Olá Kico"
Os parênteses são obrigatórios na execução de uma closure.
Como executar uma closure a partir de código Java
Como mencionei anteriormente, uma closure é na realidade um objeto: uma instância da classe groovy.lang.Closure.
Sendo assim, em Java poderiamos executar uma closure tal como no exemplo abaixo:
// O código da closure def soma = {a, b -> a + b} // O código Java Closure closure = soma soma.call({4,3}) // basta passar uma matriz representando os parametros necessários!
Escopo de execução
Veja o código abaixo:
class QualquerClasse { public void metodoQualquer() { int x = 10 def closure = { println "O valor de X é ${x}" } closure() } }
Como a closure definida em metodoQualquer() sabe da existência da variável x? Devido ao seu escopo. Uma closure possui acesso a todos os atributos definidos no bloco de código em que a mesma é definida.
Paralelamente, o método aonde a closure é definida não possui acesso às suas variáveis internas. O código abaixo por exemplo dispararia uma excessão:
class ClasseFurada { public void metodoFurado() { int x = 10; def closure = { int y = 1979 println "Não é injusto? Eu vejo ${x}, mas voce não verá minhas variaveis jamais!"} closure() print closure.y // ERRO! } }
Deixe uma resposta