Por que eu devo ler este artigo:Embora a versão 8 do Java tenha sido lançada há pouco tempo e poucos projetos a estejam usando, é um grande diferencial antecipar-se às novidades da linguagem, aprendendo como essas mudanças irão impactar sua vida futuramente.

Isto torna-se ainda mais importante quando uma dessas mudanças impõe uma forma diferente de se programar na linguagem Java, como é o caso das expressões lambda. Sendo assim, este artigo lhe introduzirá às expressões lambda e como você pode se preparar para elas. Após ler este artigo, temos certeza que você terá vontade de migrar o mais rápido possível para desde já utilizá-las em seus projetos!

O dia 25 de março de 2014 foi marcado pelo lançamento da tão aguardada versão 8 do Java. Esta nova versão introduziu dezenas de novidades, que abrangem desde novas APIs até mudanças na sintaxe da linguagem.

Já vimos algumas destas novidades na edição 120 da Java Magazine, embora não tenhamos utilizado cenários reais onde elas pudessem ser aplicadas. Entretanto, passado todo o frenesi, comum em épocas de lançamento de novas versões, ainda são poucos os projetos escritos desde o início adotando essas novas características.

Isto ocorre por diversos motivos, sendo que um deles é que cada nova versão de uma linguagem requer um tempo de adaptação por parte dos desenvolvedores.

Muitos deles sequer se acostumaram com as novidades do Java 7 e já têm à sua porta uma avalanche de mudanças que o Java 8 introduziu. Este é o cenário que você se encontra inserido agora?

Caso sim, o objetivo deste artigo é lhe ajudar a se familiarizar mais rápido com uma dessas grandes mudanças: as expressões lambda!

As expressões lambda foram bastante comentadas, aguardadas e até mesmo contestadas pela comunidade Java, pois viriam para mudar a sintaxe do Java de uma forma nunca imaginada, introduzindo conceitos somente vistos em linguagens funcionais. Com o Java 8 já lançado e ao nosso dispor, agora nos cabe aprender e pôr em prática as facilidades que essa nova funcionalidade nos brindou.

Neste contexto, o objetivo deste artigo é apresentar diversos exemplos de uso reais das expressões lambda e que lhe permitirão, mesmo que agora você não esteja em um projeto que use o Java 8, vislumbrar os possíveis cenários onde elas serão de extrema utilidade para seus futuros aplicativos.

Esperamos que este artigo, e os exemplos aqui apresentados, lhe forneça os motivos pelos quais você deveria migrar para o Java 8 apenas para ter esta nova funcionalidade ao seu dispor.

Mergulhando nas Expressões Lambda

Como tudo começo

Antes de iniciarmos um estudo mais detalhado sobre as expressões lambda, começaremos entendendo os motivos de elas terem sido introduzidas na linguagem, pois, para alguns desavisados, sua inclusão pode parecer apenas um capricho ou que o Java está incluindo características desnecessárias.

Entretanto, o cenário é muito diferente disto, pois as expressões lambda surgiram para solucionar um problema histórico e que demorou bastante tempo até ser totalmente aceito e resolvido pela comunidade de desenvolvedores Java.

Para entender melhor este panorama, precisamos relembrar da primeira versão do Java, quando o Abstract Toolkit Window (AWT) foi sugerido como ferramenta para a construção de interfaces para desktop. Em sua primeira versão, o AWT forçava que o desenvolvedor sobrescrevesse métodos herdados de suas classes para que determinados eventos, gerados a partir da interação do usuário com o aplicativo, fossem devidamente tratados.

Um exemplo desta solução pode ser visto na Listagem 1, onde o método action(), oriundo da classe java.awt.Component, é sobrescrito para que o clique em um botão seja tratado. Esta solução, entretanto, não é recomendada como uma boa prática por diversos motivos, por exemplo, devido ao forte acoplamento com a classe-pai, e logo foi substituída, a partir da versão 1.1, pelas interfaces conhecidas apenas como Listeners.

Listagem 1. Como a primeira versão do AWT tratava as interações do usuário com a tela.


  import java.applet.Applet;
 import java.awt.*;
 
 public class AWT1Exemplo extends java.awt.Frame {
     private Button botao;
 
     public void init() {
         botao = new Button("Botão");
         add(botao);
     }
 
     public boolean action(Event e, Object args) {
         // Tratar o evento aqui.
         return true;
     }
 
 }

A partir da criação dos Listeners, tornou-se desnecessário estender classes, pois, agora, precisamos implementar determinadas interfaces que contêm um ou mais métodos específicos para o tratamento de eventos. Por exemplo, há uma interface que deve ser implementada para tratar o evento gerado pelo clique em um botão (veja um exemplo na Listagem 2).

Listagem 2. Exemplo de uso dos Listeners para tratar eventos.


  import java.applet.Applet;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 
 class AWT1Exemplo extends Frame {
     private Button botao;
 
     public AWT1Exemplo() {
         botao = new Button("Botão");
         add(botao);
 
         botao.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent ae) {
                 System.out.println("Clicou")
             }
         });
     }
 }

Esta listagem nos apresenta duas novidades com relação à primeira versão do Java. A primeira novidade refere-se ao uso da interface ActionListener para tratar o evento de clique no botão, em oposição ao antigo modelo de sobrescrita de métodos da classe herdada.

A segunda novidade é a forma como uma instância desta interface foi criada, pois utilizamos uma nova característica, adicionada a partir da versão 1.1, chamada Classe Interna Anônima (Anonymous Inner Class).

Este novo recurso foi incluído com o intuito de facilitar a vida dos programadores, evitando a necessidade de criar uma classe em separado, que estende de ActionListener, apenas para tratar uma situação específica, e que não será reutilizada em outras partes do projeto, como o tratamento do clique em um botão contido em uma tela específica do aplicativo.

O problema

Após a sua criação, as Classes Internas Anônimas passaram a ser também adotadas em outros cenários, como para a instanciação de objetos do tipo Runnable com o objetivo de executar um trecho de código em paralelo através do uso das Threads. Seguindo esta mesma linha, as classes de coleções passaram a aceitar uma instância da interface Comparator para ordenar o seu conteúdo, e que, na maioria das vezes, é instanciada como uma classe anônima.

...

Quer ler esse conteúdo completo? Tenha acesso completo