BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Notícias Java 8: O estado atual do lambda

Java 8: O estado atual do lambda

Favoritos

Brian Goetz publicou uma atualização do "estado do lambda", dando informações da situação do plano de adicionar lambdas na linguagem Java, que também pode ser acompanhado pela JSR 335 e pela proposta de melhoria do Java número 126.

O plano para trazer os lambdas para a linguagem Java cobre tanto as sintaxes para funções anônimas, como planos para estender o conjunto de classes Java existentes (tal como as de Collections), com métodos que aceitem lambdas também. O objetivo é adicionar funções como map e filter, para que coleções possam ser processadas de forma mais funcional.

De modo a fornecer este comportamento nas interfaces existentes (e não somente nas classes básicas do Java), um novo tipo de método foi adicionado às interfaces, chamado método default (antes chamado método defender). 

Isto efetivamente permite que interfaces tenham implementações de métodos, de forma bem parecida com as traits do Scala ou classes abstratas do Java. Quando um método é invocado através de uma referência de interface, o compilador inicialmente delega a chamada do método para uma instância; mas se nenhuma implementação do método for encontrada, o método default declarado na interface é invocado. 

Diferentemente do que acontecia em versões anteriores da especificação, em vez de se definir um apontador para um método estático existente, a nova especificação permite métodos (mas não atributos) de interface com corpos válidos, identificados com a palavra-chave default. O seguinte exemplo adiciona o método skip() a todos os iterators:

interface Iterator<E> {
  boolean hasNext();
  E next();
  void remove();

  void skip(int i) default {
    for (; i > 0 && hasNext(); i--) next();
  }
}

Como a mudança efetivamente adiciona a implementação de herança múltipla à linguagem Java, no caso de colisões (quando o mesmo método default é herdado por dois caminhos separados), o método precisa ser redefinido na classe. Ou então um dos métodos default deve ser explicitamente chamado através do construtor: new Iterator.super.skip().

Outra recente mudança é a sugestão de alterar a sintaxe das referências a métodos, de Person#compare, inspirada no JavaDoc, para uma sintaxe mais inspirada no C++ como Person::compare. Qualquer que seja a sintaxe adotada, as referências de métodos fornecem um atalho tipado para um método que recebe um lambda.

Embora as expressões atuais do lambda não tenham sofrido muitas alterações, algumas partes da sintaxe e da terminologia vêm sendo revisadas. Por exemplo, a decisão anterior era de usar =>, adotado em C# e Scala, como sintaxe para introduzir uma expressão lambda; agora a sintaxe foi alterada para ->. Assim, uma função que retorna a negação dela mesma, pode ser escrita como int a -> -a. (Se o tipo de a puder ser inferido, ele é usado como alternativa; no caso de expressões em que o compilador não consegue identificar o tipo como byte, short, int ou long, será preciso fazer a distinção explicitamente ).

Outra mudança em terminologia ocorre para classes como Runnable e Action. Estas são interfaces com um único método abstrato, antes chamadas tipos SAM (Single Abstract Method). Para estimular o seu uso mais amplo no Java, agora são chamadas de interfaces funcionais

A mudança visa encorajar o uso desses tipos como sendo conversíveis para um tipo mais geral, partindo de uma referência a um método. Dessa forma, onde um código Java existente tem métodos que esperam instâncias de Comparator, pode-se passar agora uma expressão lambda ou um handle do método com a mesma assinatura do método compareTo() do Comparator. Embora tecnicamente o Comparator tenha dois métodos abstratos (compareTo() e equals()), ainda é visto como uma interface funcional, pois equals() já é disponibilizado em Object.

Embora as funções tipadas tenham sido consideradas (estão disponíveis em um rascunho inicial da especificação), foram rejeitadas, pelo menos por agora. Isso porque apagar uma função tipada causa problemas na versão atual da JVM. Embora não esteja descartada a inclusão das funções tipadas no futuro, há a expectativa de que interfaces funcionais baseadas em tipos sejam mais úteis em Java do que um novo tipo funcional.

Os lambdas continuam tendo uma vantagem na qual o tipo do argumento pode ser inferido sem ter que se definir explicitamente o tipo (a menos que haja necessidade de distingui-lo, como mencionado). Lambdas podem também ser recursivos e capturar estados de escopos externos (lambdas que capturam escopos externos são conhecidos como closures). A captura acontece somente para variáveis com modificador final. No entanto, a adoção de um "final efetivo", significa que o final pode ser inferido em muitos locais e não precisa ser explicitamente mencionado.

A adição de lambdas à linguagem Java, juntamente com referências a métodos, irá reduzir significativamente a quantidade de código repetitivo necessário para operações comuns. Por exemplo, para ordenar um array de strings diferenciando maiúsculas e minúsculas, poderá ser escrito:

Arrays.sort(names, String::compareToIgnoreCase)

Juntamente com os métodos default, que permitem que interfaces cresçam (como os traits do Scala) sem afetar os códigos existentes, essas mudanças deixarão o código Java muito mais conciso. Não teremos um completo híbrido objeto-funcional, mas veremos um crescimento no número de bibliotecas com estilo funcional a partir do JDK8. 

O código compilado com lambdas e métodos default não rodará em versões anteriores ao JDK8, mas será possível compilá-lo com versões mais antigas do JDK e usá-lo de maneira funcional. O processo será parecido com o que foi utilizado para trazer os tipos genéricos gradualmente para a linguagem Java.

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT