De que se trata o artigo:

O que são closures, como funcionam as três principais propostas para adição de closures à linguagem Java e um resumo da discussão sobre o assunto. O artigo mostra como instalar os protótipos de cada proposta e escrever código com closures em Java.

Para que serve:

Para apresentar o leitor a um possível novo recurso da linguagem de programação Java, permitindo assim, que forme uma opinião mais bem fundamentada sobre o assunto.

Em que situação o tema é útil:

Caso o recurso de closures venha a ser incluído na linguagem Java ou o leitor necessite usá-lo em outra linguagem de programação que já o possua.

Closure é um conceito de linguagens de programação proveniente das linguagens funcionais que também é presente em muitas linguagens orientadas a objetos (e, portanto, imperativas), como Smalltalk, Groovy, Ruby, Python e Scala.

Nos últimos dois anos se discute a adição de closures à linguagem Java. Dado o grande impacto que isso teria na linguagem – por uns julgado positivo, por outros negativo – muito se tem discutido nas conferências, blogs e portais sobre Java se o recurso deveria ser realmente adicionado e, em caso positivo, qual seria a melhor forma de fazê-lo.

Tanta discussão gerou três propostas principais para adição de closures, conhecidas pelas siglas CICE+ARM, FCM e BGGA. Uma delas, a BGGA, já é disponível experimentalmente em builds do OpenJDK. Neste artigo, apresentaremos o que são closures, as três propostas para sua adição à linguagem Java e um resumo da polêmica em torno do assunto.

Ainda que a disponibilidade de uma nova versão do Java incorporando closures seja um plano futuro e incerto, esperamos que esta discussão seja desde já proveitosa para qualquer leitor interessado em se aprofundar no paradigma de Orientação a Objetos – ou mesmo na linguagem Java, cujas inner classes já implementam uma forma restrita de closure.

O que são closures?

Segundo o FOLDOC (veja Links), closure é uma estrutura de dados que contém uma expressão e amarrações de variáveis. Já a Wikipedia a define como uma função que é avaliada em um ambiente contendo uma ou mais variáveis amarradas. As definições mais gerais tratam qualquer elemento que possua um ambiente de variáveis fechado (daí o nome “closures”) que seja um cidadão de primeira classe (veja o quadro “Cidadãos de primeira classe”) como closures. Neste sentido, objetos Java e ponteiros para função em C poderiam ser chamados de closures.

Amarração (em inglês, “binding”) é a associação entre entidades de programação, tal como, neste caso, entre o nome de uma variável e seu valor.

Cidadãos de primeira classe

No contexto de linguagens de programação, “cidadãos de primeira” classe são entidades da linguagem que podem ser utilizadas sem restrições, ou seja, podem ser expressas como literais, armazenadas em variáveis, passadas como parâmetros de procedimentos / funções, retornadas como resultados, criadas dinamicamente, etc.

Por exemplo, em Java, métodos não podem ser passados como parâmetros, exceto com o uso de reflexão. Já em C é possível passar ponteiros para funções, porém não é possível criar ou modificar funções em tempo de execução. Neste caso, dizemos que funções de C e métodos Java são cidadãos de segunda classe. Já em FORTRAN 66, strings não podem ser armazenadas em variáveis (realmente não há como).

O termo original em inglês é “first class citizens”, também encontrado na literatura como first class “objects” (objetos), “values” (valores) ou “entities” (entidades).

Na prática, e em termos mais simples (talvez até simplista), closures são blocos de código (conjunto de expressões) que podem acessar variáveis do seu escopo e que podem ser criados dinamicamente, armazenados em variáveis e passados como parâmetros. A Listagem 1 traz um exemplo bem simples de uso de closures na linguagem Groovy.

Nos exemplos de código, onde são mostradas closures em várias linguagens ou variantes de closures, destacaremos em negrito todas as closures; e em alguns casos outros elementos de linguagem relacionados ao suporte de closures.

def clos = { println "Olá!" }  // Definindo a closure e armazenando-a
 clos()                         // Invocando a closure
 executaClosure(clos)           // Passando como parâmetro
 def executaClosure(closure) {
   closure()                    // Invocando a closure passada
 }
Listagem 1. Exemplos de uso de closures em Groovy

Neste exemplo, uma closure que imprime “Olá!” na tela é definida e armazenada na variável clos. Quando esta variável é chamada como se fosse um método (clos()), o código definido no bloco é executado. A closure pode ser passada como parâmetro para o método executaClosure() e executada dentro do mesmo, imprimindo a mesma mensagem. Outro exemplo, desta vez com passagem de parâmetros e com amarração de variáveis, é mostrado na Listagem 2.

def soma = { a, b -> a + b }  
 def resultado = soma(7, 5)
 println resultado             // Imprime 12
 def dobroResultado = { println resultado * 2 }
 dobroResultado()              // Imprime 24
 resultado++
 dobroResultado()              // Imprime 26
Listagem 2. Exemplo de closures com passagem de parâmetros e com amarração de variáveis em Groovy

É interessante notar que a closure armazenada na variável dobroResultado faz referência à uma variável definida fora da closure (no caso, resultado), e que, ao alterar o valor desta variável, o valor impresso com a invocação da closure também muda.

Um pouco de história

Na década de 50, pesquisadores do MIT (Massachusetts Institute of Technology, nos EUA) criaram a linguagem de programação funcional Lisp. Um dos recursos desta linguagem era o das expressões lambda. A palavra-chave lambda pode ser usada para criar uma expressão que funciona como uma função anônima, podendo ser atribuída a uma variável ou passada como parâmetro e invocada posteriormente.

...

Quer ler esse conteúdo completo? Tenha acesso completo