Skip to content

Latest commit

 

History

History
184 lines (158 loc) · 8.51 KB

File metadata and controls

184 lines (158 loc) · 8.51 KB

Expressões Lambda (Lambda Expression)

Objetivo
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:

  1. Uma lista de parâmetros, separados por vírgula

    • Algumas vezes possui parênteses

    • Algumas vezes possui o tipo das variáveis

  2. O "arrow token", que sempre é escrito como ->

  3. 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")

  1. Expressões lambda podem ser entendidas como uma forma diferente de declarar classes anônimas.

    src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AnonymousClass.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AnonymousClass.java[role=include]

    Veja que no exemplo acima é instanciada uma Thread com uma instância anônima de Runnable. Na segunda parte, é feito a mesma coisa de forma muito mais simples utilizando uma expressão lambda.

  2. 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.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_FunctionalInterface.java[role=include]
    Saída no console
    executei 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 interface Executavel, está sendo implementado dentro da expressão lambda.

  3. Existem muitos métodos já disponíveis no Java 8 que se beneficiam da sintaxe de expressões lambda, como o forEach de listas.

    src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_ForEach.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_ForEach.java[role=include]
    Saída no console
    1
    2
    3
    4
    5

    Veja que o novo método forEach executa 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.

  4. Declarações de expressões lambda podem ser completas ou simplificadas.

    src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_SimpleComplete.java
    link:../../../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.

  5. Os parênteses só podem ser omitidos caso não haja a declaração do tipo, e haja apenas um único argumento.

  6. Expressões lambda que NÃO possuem argumentos também precisam dos parênteses.

    src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Parenthesis.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Parenthesis.java[role=include]
  7. É 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.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Block.java[role=include]
  8. Ao tornar explícito o tipo de um dos argumentos, é obrigatório informar de todos.

    src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_VarType.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_VarType.java[role=include]
  9. Não é permitido declarar variáveis com o mesmo nome dentro da expressão lambda.

    src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Shadowing.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Shadowing.java[role=include]
  10. É 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.java
    link:../../../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.

  11. 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.java
    link:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_TypeInference.java[role=include]

    No exemplo anterior, apenas o método run da interface funcional Application retorna uma String, enquanto o método execute da interface funcional Executavel não retorna nada (void). Isso é diferença suficiente para o compilador saber qual método chamar cada vez que rode é invocado.

    Na primeira chamada ao método rode, como a expressão lambda passada retorna uma String, o compilador entende que essa expressão lambda é uma implementação da interface Application, pois o método run também retorna uma String.

    Na segunda chamada ao método rode, como a expressão lambda não retorna nada (apenas imprime a String "executando"), o compilador entende que essa expressão lambda é uma implementação da interface Executavel, pois o método execute também não retorna nada.

  12. 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.java
    link:../../../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 tipo Piloto quanto Corredor, e não há como o compilador descobrir qual o desenvolvedor de fato quis utilizar.

Referências
  • 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.