Describe a lambda expression; refactor the code that uses an anonymous inner class to use a lambda expression; describe type inference and target typing. - Descrever uma expressão lambda; refatorar código que usa classes anônimas internas para usar expressões lambda; descrever a inferência de tipos e tipos esperados.
Expressões Lambda são parecidas com classes anônimas, porém só possuem a implementação dos métodos. Por isso, são como "métodos anônimos", que podem ser passados via variáveis.
É essencial o entendimento de funções lambda, e das variações em sua sintaxe, para compreender as próximas seções de Interfaces Funcionais Pré-Construídas e de Referências a métodos.
A expressão lambda possui 3 partes:
-
Uma lista de parâmetros, separados por vírgula
-
Algumas vezes possui parênteses
-
Algumas vezes possui o tipo das variáveis
-
-
O "arrow token", que sempre é escrito como
-> -
Um corpo, que pode ou não estar entre chaves
-
Pode possuir mais de uma linha
-
Algumas vezes possui um
return -
Algumas vezes possui ponto e vírgula
-
Exemplos de expressões lambda:
-
i → System.out.println(i) -
(Integer i) → System.out.println(i) -
(Integer i) → { System.out.println(i); } -
(Integer i) → { return i + 1; } -
(i, j, k) → { return i + j + k; } -
(i, j, k) → System.out.println(i + j + k) -
() → System.out.println("nada")
-
Expressões lambda podem ser entendidas como uma forma diferente de declarar classes anônimas.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AnonymousClass.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AnonymousClass.java[role=include]
Veja que no exemplo acima é instanciada uma
Threadcom uma instância anônima deRunnable. Na segunda parte, é feito a mesma coisa de forma muito mais simples utilizando uma expressão lambda. -
Expressões lambda são sempre utilizadas para criar instâncias de interfaces funcionais, ou seja, interfaces que possuem apenas um único método abstrato.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_FunctionalInterface.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_FunctionalInterface.java[role=include]
Saída no consoleexecutei com classe anônima executei com expressão lambda
Veja que no exemplo acima o mesmo método
executeEApresenteMensagemé invocado duas vezes. Na primeira vez é passada uma nova classe anônima. Na segunda vez é passado uma expressão lambda.Veja também que seria impossível criar uma expressão lambda caso a interface não fosse funcional, ou seja, tivesse mais de um método abstrato. O compilador não saberia identificar que o método
execute, da interfaceExecutavel, está sendo implementado dentro da expressão lambda. -
Existem muitos métodos já disponíveis no Java 8 que se beneficiam da sintaxe de expressões lambda, como o
forEachde listas.src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_ForEach.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_ForEach.java[role=include]
Saída no console1 2 3 4 5
Veja que o novo método
forEachexecuta a expressão lambda passada como parâmetro para cada item da lista, imprimindo todos no console. A expressão lambda recebe como parâmetro um número, que é o número da lista.Neste caso, a interface funcional que está sendo implementada pela expressão lambda é chamada
Consumer. Ela será explicada em detalhes em uma seção posterior, juntamente com outras interfaces funcionais padrões do Java 8. Nesta seção é importante apenas entender o que são as expressões lambda e como é sua sintaxe. -
Declarações de expressões lambda podem ser completas ou simplificadas.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_SimpleComplete.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_SimpleComplete.java[role=include]
As duas funções lambda acima são idênticas, porém uma é mais explícita do que a outra.
-
Os parênteses só podem ser omitidos caso não haja a declaração do tipo, e haja apenas um único argumento.
-
Expressões lambda que NÃO possuem argumentos também precisam dos parênteses.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Parenthesis.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Parenthesis.java[role=include]
-
É obrigatória a utilização de chaves, ponto e vírgula e
return(caso a função retorne algum valor) em expressões lambda com mais de uma linha.src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Block.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Block.java[role=include]
-
Ao tornar explícito o tipo de um dos argumentos, é obrigatório informar de todos.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_VarType.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_VarType.java[role=include]
-
Não é permitido declarar variáveis com o mesmo nome dentro da expressão lambda.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Shadowing.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Shadowing.java[role=include]
-
É permitido acessar variáveis externas dentro da expressão lambda, mas somente variáveis finais ou variáveis que não são alteradas.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AccessExternalVar.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AccessExternalVar.java[role=include]
Perceba que o compilador identifica que a variável
x3é alterada no final do método, e por isso, não permite que ela seja utilizada na expressão lambda. -
Em situações de ambiguidade, o compilador tenta descobrir o tipo da expressão lambda utilizando o contexto.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_TypeInference.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_TypeInference.java[role=include]
No exemplo anterior, apenas o método
runda interface funcionalApplicationretorna umaString, enquanto o métodoexecuteda interface funcionalExecutavelnão retorna nada (void). Isso é diferença suficiente para o compilador saber qual método chamar cada vez querodeé invocado.Na primeira chamada ao método
rode, como a expressão lambda passada retorna umaString, o compilador entende que essa expressão lambda é uma implementação da interfaceApplication, pois o métodoruntambém retorna umaString.Na segunda chamada ao método
rode, como a expressão lambda não retorna nada (apenas imprime aString"executando"), o compilador entende que essa expressão lambda é uma implementação da interfaceExecutavel, pois o métodoexecutetambém não retorna nada. -
Se não for possível descobrir o tipo da expressão lambda, ocorre erro de compilação.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Ambiguity.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Ambiguity.java[role=include]
No exemplo anterior, como as duas interfaces funcionais possuem métodos com retorno
void, o compilador não sabe qual das duas está sendo instanciada na expressão lambda, e ocorre erro de compilação. A expressão lambda, nesse exemplo, poderia ser tanto do tipoPilotoquantoCorredor, e não há como o compilador descobrir qual o desenvolvedor de fato quis utilizar.
-
Implementing Functional Interfaces with Lambdas
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 55). Wiley. Edição do Kindle.
-
Using Variables in Lambdas
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 172). Wiley. Edição do Kindle.
-
Lambda Expressions and Functional Interfaces: Tips and Best Practices.
-
Lambda Expressions. The Java™ Tutorials.