Skip to content

Commit 4afd9a7

Browse files
committed
feat(lambda-expression): regras e exemplos
Regras e exemplos da seção Expressões Lambda. Issue #20
1 parent cb8677b commit 4afd9a7

10 files changed

Lines changed: 309 additions & 0 deletions

book/04-lambda/sections/02-lambda-expression.asc

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,118 @@ Describe a lambda expression; refactor the code that uses an anonymous inner cla
1010
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.
1111
--------------------------------------------------
1212

13+
Expressões Lambda são parecidos 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.
14+
15+
A expressão lambda possui 3 partes:
16+
17+
* Uma lista de parâmetros, separados por vírgula; algumas vezes possui parênteses; algumas vezes possui o tipo das variáveis.
18+
* O "arrow token", que sempre é escrito como `\->`
19+
* 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.
20+
21+
Exemplos de expressões lambda:
22+
23+
* `i -> System.out.println(i)`
24+
* `(Integer i) -> System.out.println(i)`
25+
* `(Integer i) -> { System.out.println(i); }`
26+
* `(Integer i) -> { return i + 1; }`
27+
* `(i, j, k) -> { return i + j + k; }`
28+
* `(i, j, k) -> System.out.println(i + j + k)`
29+
* `() -> System.out.println("nada")`
30+
31+
. Expressões lambda podem ser entendidas como uma forma diferente de declarar classes anônimas.
32+
+
33+
[source,java,indent=0]
34+
.{java-package}/lambdaexpression/LambdaExpression_AnonymousClass.java
35+
----
36+
include::{section-java-package}/lambdaexpression/LambdaExpression_AnonymousClass.java[tag=code]
37+
----
38+
+
39+
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.
40+
41+
. Declarações de expressões lambda podem ser completas ou simplificadas.
42+
+
43+
[source,java,indent=0]
44+
.{java-package}/lambdaexpression/LambdaExpression_SimpleComplete.java
45+
----
46+
include::{section-java-package}/lambdaexpression/LambdaExpression_SimpleComplete.java[tag=code]
47+
----
48+
+
49+
As duas funções lambda acima são idênticas, porém uma é mais explícita do que a outra.
50+
51+
. Os parênteses só podem ser omitidos caso não haja a declaração do *tipo*, e haja apenas *um único* argumento.
52+
. Expressões lambda que NÃO possuem argumentos também precisam dos parênteses.
53+
+
54+
[source,java,indent=0]
55+
.{java-package}/lambdaexpression/LambdaExpression_Parenthesis.java
56+
----
57+
include::{section-java-package}/lambdaexpression/LambdaExpression_Parenthesis.java[tag=code]
58+
----
59+
60+
. Caso a expressão lambda possua mais de uma linha, é obrigatória a utilização de chaves, ponto e vírgula e return (se a função retornar algum valor).
61+
+
62+
[source,java,indent=0]
63+
.{java-package}/lambdaexpression/LambdaExpression_Block.java
64+
----
65+
include::{section-java-package}/lambdaexpression/LambdaExpression_Block.java[tag=code]
66+
----
67+
68+
. Ao tornar explícito o tipo de um dos argumentos, é obrigatório informar de todos.
69+
+
70+
[source,java,indent=0]
71+
.{java-package}/lambdaexpression/LambdaExpression_VarType.java
72+
----
73+
include::{section-java-package}/lambdaexpression/LambdaExpression_VarType.java[tag=code]
74+
----
75+
76+
. Não é permitido declarar variáveis com o mesmo nome dentro da expressão lambda.
77+
+
78+
[source,java,indent=0]
79+
.{java-package}/lambdaexpression/LambdaExpression_Shadowing.java
80+
----
81+
include::{section-java-package}/lambdaexpression/LambdaExpression_Shadowing.java[tag=code]
82+
----
83+
84+
. É permitido acessar variáveis externas dentro da expressão lambda, mas somente variáveis finais ou variáveis que não são alteradas.
85+
+
86+
[source,java,indent=0]
87+
.{java-package}/lambdaexpression/LambdaExpression_AccessExternalVar.java
88+
----
89+
include::{section-java-package}/lambdaexpression/LambdaExpression_AccessExternalVar.java[tag=code]
90+
----
91+
+
92+
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.
93+
94+
. Em situações de ambiguidade, o compilador tenta descobrir o tipo da expressão lambda utilizando o contexto.
95+
+
96+
[source,java,indent=0]
97+
.{java-package}/lambdaexpression/LambdaExpression_TypeInference.java
98+
----
99+
include::{section-java-package}/lambdaexpression/LambdaExpression_TypeInference.java[tag=code]
100+
----
101+
+
102+
No exemplo anterior, apenas o método `corra` da interface funcional `Piloto` retorna uma `String`, por isso o compilador sabe que deve chamá-lo.
103+
104+
. Se não for possível descobrir o tipo da expressão lambda, ocorre erro de compilação.
105+
+
106+
[source,java,indent=0]
107+
.{java-package}/lambdaexpression/LambdaExpression_Ambiguity.java
108+
----
109+
include::{section-java-package}/lambdaexpression/LambdaExpression_Ambiguity.java[tag=code]
110+
----
111+
+
112+
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.
113+
13114
.Referências
14115
****
15116
16117
* Implementing Functional Interfaces with Lambdas
17118
+
18119
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 55). Wiley. Edição do Kindle.
19120
121+
* Using Variables in Lambdas
122+
+
123+
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 172). Wiley. Edição do Kindle.
124+
20125
* https://www.baeldung.com/java-8-lambda-expressions-tips[Lambda Expressions and Functional Interfaces: Tips and Best Practices.]
21126
22127
* https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[Lambda Expressions.] The Java™ Tutorials.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
import java.util.function.UnaryOperator;
4+
5+
public class LambdaExpression_AccessExternalVar {
6+
7+
// tag::code[]
8+
public static void main(String[] args) {
9+
final Double x1 = 2.0;
10+
Double x2 = 2.0;
11+
Double x3 = 2.0;
12+
13+
// COMPILA - variável externa 'x1' é final e pode ser utilizada na expressão lambda
14+
UnaryOperator<Double> elevarAoX1 = (Double y) -> Math.pow(y, x1);
15+
16+
// COMPILA - variável externa 'x2' não é final, mas nunca é alterada, então pode ser utilizada dentro da expressão lambda
17+
UnaryOperator<Double> elevarAoX2 = (Double y) -> Math.pow(y, x2);
18+
19+
// NÃO COMPILA - variável externa 'x3' é alterada dentro desse método, então não pode ser utilizada dentro da expressão lambda
20+
UnaryOperator<Double> elevarAoX3 = (Double y) -> Math.pow(y, x3);
21+
22+
x3 = 3.0; // alteração da variável x3 não permite que ela seja utilizada em expressões lambda
23+
}
24+
// end::code[]
25+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
public class LambdaExpression_Ambiguity {
4+
5+
// tag::code[]
6+
@FunctionalInterface
7+
interface Corredor {
8+
void corra();
9+
}
10+
11+
@FunctionalInterface
12+
interface Piloto {
13+
void corra();
14+
}
15+
16+
static class Executor {
17+
void execute(Corredor corredor) {
18+
corredor.corra();
19+
}
20+
21+
String execute(Piloto piloto) {
22+
piloto.corra();
23+
return "correndo";
24+
}
25+
}
26+
27+
public static void main(String[] args) {
28+
Executor executor = new Executor();
29+
// NÃO COMPILA - não é possível determinar o tipo da expressão lambda abaixo
30+
executor.execute(() -> System.out.println("execute"));
31+
}
32+
// end::code[]
33+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
public class LambdaExpression_AnonymousClass {
4+
5+
public static void main(String[] args) {
6+
// tag::code[]
7+
// com classe anônima
8+
new Thread(new Runnable() {
9+
@Override
10+
public void run() {
11+
System.out.println("Executando.");
12+
}
13+
}).run();
14+
15+
// com expressão lambda
16+
new Thread(() -> System.out.println("Executando.")).run();
17+
// end::code[]
18+
}
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
import java.util.function.Consumer;
4+
import java.util.function.UnaryOperator;
5+
6+
public class LambdaExpression_Block {
7+
8+
public static void main(String[] args) {
9+
// tag::code[]
10+
UnaryOperator<Double> elevarAoQuadrado = (Double x) -> {
11+
double pow = Math.pow(x, 2);
12+
return pow;
13+
};
14+
15+
Consumer<Double> imprime = (Double x) -> {
16+
double pow = Math.pow(x, 2);
17+
System.out.println(pow);
18+
};
19+
// end::code[]
20+
}
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
import java.util.function.UnaryOperator;
4+
5+
public class LambdaExpression_Parenthesis {
6+
7+
public static void main(String[] args) {
8+
// tag::code[]
9+
// NÃO COMPILA - parênteses são obrigatórios ao declarar o tipo da variável da expressão lambda
10+
UnaryOperator<Double> elevarAoQuadrado = Double x -> Math.pow(x, 2);
11+
12+
// NÃO COMPILA - é obrigatório utilizar parênteses quando há mais de uma variável na expressão lambda
13+
BinaryOperator<Double> elevarAoX = y, x -> Math.pow(y, x);
14+
15+
// NÃO COMPILA - é obrigatório utilizar parênteses quando não há variáveis
16+
Supplier<Double> elevar2aoQuadrado = -> Math.pow(2, 2);
17+
18+
// COMPILA - parênteses vazios quando não há variáveis
19+
Supplier<Double> elevar2aoQuadrado = () -> Math.pow(2, 2);
20+
// end::code[]
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
import java.util.function.BinaryOperator;
4+
import java.util.function.UnaryOperator;
5+
6+
public class LambdaExpression_Shadowing {
7+
8+
// tag::code[]
9+
public static void main(String[] args) {
10+
Double x = 2.0; // variável 'x' no método
11+
12+
// NÃO COMPILA - a variável com nome 'x' já existe e não pode ser declarada nas variáveis da expressão lambda
13+
BinaryOperator<Double> elevarAoX = (Double y, Double x) -> Math.pow(y, x);
14+
15+
// NÃO COMPILA - a variável com nome 'x' já existe e não pode ser declarada no corpo da expressão lambda
16+
UnaryOperator<Double> elevarAoQuadrado = (Double y) -> {
17+
Double x = 2.0;
18+
return Math.pow(y, x);
19+
};
20+
}
21+
// end::code[]
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
import java.util.function.UnaryOperator;
4+
5+
public class LambdaExpression_SimpleComplete {
6+
7+
public static void main(String[] args) {
8+
// tag::code[]
9+
// expressão lambda completa
10+
UnaryOperator<Double> elevarAoQuadrado1 = (Double x) -> { return Math.pow(x, 2); };
11+
// expressão lambda simplificada
12+
UnaryOperator<Double> elevarAoQuadrado2 = (x) -> Math.pow(x, 2);
13+
// end::code[]
14+
}
15+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
public class LambdaExpression_TypeInference {
4+
5+
// tag::code[]
6+
@FunctionalInterface
7+
interface Corredor {
8+
void corra();
9+
}
10+
11+
@FunctionalInterface
12+
interface Piloto {
13+
String corra();
14+
}
15+
16+
static class Executor {
17+
void execute(Corredor corredor) {
18+
corredor.corra();
19+
}
20+
21+
String execute(Piloto piloto) {
22+
return piloto.corra();
23+
}
24+
}
25+
26+
public static void main(String[] args) {
27+
Executor executor = new Executor();
28+
String s = executor.execute(() -> "execute");
29+
}
30+
// end::code[]
31+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.j6toj8.lambda.lambdaexpression;
2+
3+
import java.util.function.UnaryOperator;
4+
5+
public class LambdaExpression_VarType {
6+
7+
public static void main(String[] args) {
8+
// tag::code[]
9+
// NÃO COMPILA - caso o tipo de um dos parâmetros for informado, é necessário informar de todos eles
10+
UnaryOperator<Double> elevarAoX = (Double y, x) -> Math.pow(y, x);
11+
12+
// COMPILA - todos os parâmetros com tipos informados
13+
UnaryOperator<Double> elevarAoX2 = (Double y, Double x) -> Math.pow(y, x);
14+
// end::code[]
15+
}
16+
}

0 commit comments

Comments
 (0)