Trabalhando com closures no Java 8

Atenção! Esse post se refere a uma versão beta do Java 8. Essa sintaxe mudou. Veja neste post atualizado como trabalhar com essa nova versão 8 do Java.

java logoCriar em Java um simples Runnable ou ActionListener pode ocupar muitas linhas de código. A solução preferida dos programadores hoje é usar as classes anônimas do Java:

Runnable r = new Runnable() {
  public void run() {
    System.out.println("Caelum"); 
  }
};
new Thread(r).start();

Depois de muitas propostas para closures no Java, a proposta atual de Lambdas para o Java 8 permite omitir a declaração do método, no caso de haver apenas um método abstrato naquela classe abstrata/interface (single abstract method):

Runnable r = #{System.out.println("Caelum")};
new Thread(r).start();

Mais ainda: o compilador consegue inferir um passo adiante, descobrindo que há um construtor em Thread que recebe como argumento uma interface que possui apenas um método abstrato. Repare que agora não precisamos escrever nem Runnable, nem run:

new Thread(#{System.out.println("Caelum")}).start();

Esses recursos, somados aos polêmicos defender methods (que permitem indicar “defaults” para métodos em interfaces), permitirão escrever lista.sortBy(#Usuario.getNome), muito mais sucinto do que invocar Collections.sort(lista, ...) passando um new Comparator() {...} que invoca u1.getNome.compareTo().

Como rodar esses testes? O Java 7 está previsto já para junho, mas infelizmente não contemplará muitos dos esperados avanços na linguagem. Esses ficarão para meados de 2012, com o Java 8, mas você já pode experimentá-los. Para isso, precisa ter o Java 7 instalado (mac aqui). Depois precisa clonar o repositório do langtools:

hg clone http://hg.openjdk.java.net/lambda/lambda/langtools

Para compilar esse projeto, de dentro de langtools/make, executamos o ant passando referência para os diretórios de instalação do seu Java 6 e Java 7:

ant -Dboot.java.home=/usr/lib/jvm/java-6-sun -Dtarget.java.home=/algumdiretorio/jdk1.7.0 build-all-tools

Para compilar nosso código que utilize esses recursos do Java 8, precisamos do classes.jar gerado em dist/bootstrap/lib, que contem as classes necessárias para o compilador e também para a execução:

jdk1.7.0/bin/java -cp classes.jar com.sun.tools.javac.Main Classe.java

E para executar:

jdk1.7.0/bin/java -cp classes.jar:. Classe

Você já está pronto para verificar, criticar e comentar. A lista de discussão do projeto Lambda está bastante movimentada. E o que você achou das novidades do Java 8? Comente aqui no Blog e dê sua opinião.

23 Comentários

  1. Cesimar Xavier 11/01/2011 at 12:44 #

    Muito bom!!

  2. Pablo Cantero 11/01/2011 at 12:56 #

    “no caso de haver apenas um método abstrato naquela classe abstrata/interface (single abstract method)”

    Só funcionará se tiver apenas um método abstrato?

    Se Java tivesse um bom suporte para closure, vcs também acham que muitos design patterns irão perder força?

  3. Leandro Silva 11/01/2011 at 14:14 #

    Booooooa, Paulo! :)

  4. Ricardo Herrmann 11/01/2011 at 22:13 #

    Respondendo à pergunta do Pablo afirmativamente, o Peter Norvig identificou que, em Lisp ou Dylan, 16 dos 23 patterns do GoF são invisíveis ou mais simples (http://www.norvig.com/design-patterns, slide 10) devido a características destas linguagens. No caso de closures/lambdas/funções de primeira classe, isso inclui Command, Strategy, Template Method e Visitor.

  5. Paulo Silveira 12/01/2011 at 00:13 #

    @Pablo realmente so funciona com apenas um metodo, ou você toma um “the target type of a lambda conversion has multiple non-overriding abstract methods” Com mais de um, como ele saberia qual é um e qual é outro? Uma sintaxe facilitada para isso nao ficaria muito longe de uma classe anonima.

    E complementando a resposta do @herrmann, realmente vai resolver alguns design patterns, assim como o Java EE 5 eliminou a necessidade de muitos dos antigos Core J2EE Patterns.

  6. Pablo Cantero 12/01/2011 at 01:57 #

    @Paulo, na verdade eu pensava em blocos mais explícitos, permitindo especificar o método, mas realmente pode ficar muito próximo de uma classe anônima

    @herrmann, obrigado pela resposta! Muito bom saber

  7. Alexandre Gazola 12/01/2011 at 10:11 #

    Legal!!!

  8. Jazz 16/01/2011 at 18:21 #

    - Mas o que realmente é proposto do Java 7 para o Java 8 ? Closures é algo certo no Java em sua especificação , ou estamos falando mesmo do uso de Lambda ?

  9. Paulo Silveira 17/01/2011 at 07:35 #

    @Jazz, a especificação ainda não tem proposta definida, há apenas a afirmação de que o projeto Lambda estará incluso no Java 8:
    http://jcp.org/en/jsr/detail?id=335

    Com as closures funcionarão exatamente no Java 8 ainda é uma dúvida. Esse código que exemplifiquei é ainda uma tentativa, poderá mudar um pouco.

  10. Jazz 17/01/2011 at 17:17 #

    @Silveira

    Fiz uma pesquisa no assunto sobre Lambda e encontrei um material do InfoQ que não havia lido, esta no link http://bit.ly/hk7RMk Lambdas in Java: An In-Depth Analysis , deu uma clareada, e sobre a JSR 335 Lambda Expressions percebi que em vários fóruns vem sofrendo criticas devido a verbosidade no código discussão http://bit.ly/fQyUvK , mas algo à se evoluir quando efetivada, com certeza.

  11. Paulo Silveira 17/01/2011 at 17:24 #

    @JazzDuran é isso mesmo, muita discussão. Essa nova proposta é menos verborrágica, bem melhor que essas discutidas em 2008.

  12. Paulo Silveira 25/01/2011 at 18:48 #

    E pra quem quiser ir além das closures e testar mais recursos futuros, vale ler esse novo post:
    http://www.javarants.com/2011/01/22/using-closures-method-handles-and-extension-methods-in-java-8-jsr-335/

  13. William Cruz Gouvea 27/01/2011 at 12:46 #

    Achei interessante essa forma abordada no artigo, lembra muito as funções anonimas já usadas em Clojure que por um acaso já são Runnable e Callable!

    Parabens pelo execelente conteudo!

  14. Diogo Silvério 28/01/2011 at 11:38 #

    Bom abordagem, como de costume.

    Sou sempre a favor da evolução, mas esta feature não me enche os olhos como as outras.

  15. Caio Oliveira 21/02/2011 at 14:32 #

    Muito interessante. Java menos verboso.

  16. Lennon Jesus 24/02/2011 at 11:56 #

    Maneiríssimo!

    Aqui funcionou perfeitamente, com exceção do fato de não ter sido gerado nenhum classes.jar.

    Vamos torcer pra eles agilizarem o Java 8.

  17. Ricardo 20/11/2012 at 13:07 #

    A linguagem ainda tem muito o que melhorar, perde de longe para o vb.net pu c#.

    O fato de nao ter um auto-corretor de codigos quando voce digira uma letra maiuscula ou minuscula faz-se perder muito tempo corrigindo os erros de digitação. Alem disso trabalhar com uma “penca” de chaves ou colchetes só faz confundir ainda mais.

    Enquanto a SUN não mudar isso eu considero uma linguagem inviavel para programadores.

    Up C#!!!!

Deixe uma resposta