Expressões lambda são a novidade do momento no ecossistema Java. Uma expressão lambda é um bloco de código que pode ser passado como parâmetro para ser executado mais tarde pelo código. Parece algo bem simples para todo o alvoroço da comunidade Java em torno dessa novidade, mas expressões lambda facilitam muitas coisas e as novidades envolvendo essa implementação na plataforma Java são muito interessantes, inclusive sobre o paradigma funcional envolto a lambdas.
Um dos primeiros aspectos de confusão em relação a lambdas é o paradigma de programação. Muita gente confunde essa novidade com voltar a programar de forma funcional. Isso é um grande equívoco, a programação funcional que vemos florescer não vem para substituir a orientação a objetos, mas vem para facilitar as coisas onde a programação funcional se sai melhor, como em eventos e concorrência. Esses pequenos blocos de código funcional se mesclam a orientação a objetos com o objetivo de simplificar as coisas, tornando o código mais elegante e robusto.
Motivação para uso de lambdas
Existe uma série de padrões que possibilitam a execução de determinadas ações em um determinado momento no futuro. Considere a ordenação de Strings por tamanho implementada com um Comparator, ilustrada nas linhas de código a seguir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.gabrielamorim; import java.util.Arrays; import java.util.Comparator; public class Java8Test { public static void main(String[] args) { String[] words = {"ball", "book", "computer", "car", "elephant", "nice"}; Arrays.sort(words, new LengthComparator()); for(String word : words) { System.out.println(word); } } } class LengthComparator implements Comparator<String> { @Override public int compare(String string1, String string2) { return Integer.compare(string1.length(), string2.length()); } } |
A classe LengthComparator é um Comparator que compara duas Strings por tamanho e é passado por parâmetro para o método Arrays.sort junto com um array contendo as Strings para serem ordenadas.
Esse tipo de código é trivial, mas como ficaria a mesma ordenação utilizando lambda? Ficaria assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.gabrielamorim; import java.util.Arrays; import java.util.Comparator; public class Java8Test { public static void main(String[] args) { String[] words = {"ball", "book", "computer", "car", "elephant", "nice"}; Arrays.sort(words, (first, second) -> Integer.compare(first.length(), second.length())); for(String word : words) { System.out.println(word); } } } |
Muito mais simples e fácil de entender! Repare que nem é mais preciso da classe LenghtComparator , que existia apenas para comparar Strings por tamanho encapsulando o código responsável pela comparação.
Sintaxe Lambda
1 |
(parâmetros) -> { expressão } |
Uma expressão lambda é um bloco de código junto com a especificação de variáveis que podem ser passadas para a mesma. A expressão lambda do exemplo acima é a que segue:
1 |
(String first, String second) -> Integer.compare(first.length(), second.length()) |
Caso a expressão seja composta por mais de uma linha de código, deve ser delimitada por chaves { }. Se a expressão não tiver parâmetros, ainda assim devem-se usar parênteses:
1 2 |
//expressão lambda sem parâmetros () -> { expressão } |
Interfaces Funcionais
Há um novo conceito em Java, o de interface funcional. Uma interface funcional é uma interface com apenas um método abstrato. A interface Comparator é uma interface funcional, existe para encapsular apenas uma função.
Expressões lambda são convertidas em interfaces funcionais durante o tempo de execução e, na verdade, a conversão de uma expressão lambda em uma interface funcional é a única coisa que pode ser feito com expressões lambda em Java.
A expressão lambda deve respeitar o contrato da interface ao qual ela será convertida, deve declarar os mesmos parâmetros que e o tipo de retorno deve ser o mesmo. Se a interface não declarar que lança exceções, a expressão lambda também não pode lançar exceções checadas.
Escopo de variáveis e closures
As regras de escopo de variáveis são as mesmas para lambdas. Além disso, lambdas podem fazer uso de variáveis fora do bloco da expressão lambda. Como uma expressão lambda é um bloco de código a ser executado no futuro, quando ele for executado, as variáveis que ele utiliza podem não estar mais disponíveis. Essas variáveis são na verdade encapsuladas junto à expressão lambda em um objeto para serem utilizadas quando a expressão for executada. Variáveis encapsuladas junto à expressão lambda, conhecidas como free variables, é o conceito de closure.
1 Reply to “Java 8: Expressões Lambda, Closures, Interfaces Funcionais e um pouco mais”