Baseado nos cursos da Softblue
Expressões Lambda
Maior inovação da versão 8 do Java
O nome lambda vem do conceito matemático de cálculo lambda
Expressões lambda trazem o Java mais próximo do paradigma de programação funcional
Uma expressão lambda pode ser considerada como um objeto
– Pode ser referenciada por uma variável
– Pode ser passada como parâmetro para métodos e utilizada como retorno
- Em Java, uma expressão lambda é utilizada em substituição a uma inner class anônima
1
2
3
4
5
6
7
8
9
10
11
12
Runnable r = new Runnable() {
@Override
public void run() { //Inner class anônima
System.out.println("ABC");
}
};
new Thread(r).start();
Runnable r = () -> System.out.println("ABC");//Expressão lambda
new Thread(r).start();
new Thread(() -> System.out.println("ABC")).start();//Expressão lambda
Resultado: código mais simples e intuitivo
- Uma expressão lambda é representada da seguinte forma:
1
(Parâmetros) -> { Corpo } //operador arrow
Exemplos de sintaxe:
Interfaces funcionais
- Uma interface funcional tem duas características
É uma interface
Possui apenas 1 método
- Uma expressão lambda pode ser atribuída a uma variável de uma interface funcional
1
2
3
4
Runnable r = () -> System.out.println("ABC");
Comparator<String> c = (s1, s2) -> s1.compareTo(s2);
Comparable<String> c = s -> 0;
ActionListener l = e -> System.out.println("123");
Interfaces que já pertenciam ao Java agora passam a ser interfaces funcionais
@FunctionalInterface
- Esta annotation define uma interface como interface funcional
1
2
3
4
@FunctionalInterface
public interface Generator {
public String generate();
}
Seu uso não é obrigatório
Se @FunctionalInterface for utilizada, o compilador checa se a interface define apenas 1 método
Interface funcional: Predicate
1
2
3
4
5
6
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Predicate<String> p = s -> s.length() > 5; //true se o tamanho da String for maior do que 5
O tipo T define o tipo a ser testado
Retorna um boolean
Interface funcional: Consumer
1
2
3
4
5
6
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Consumer<Integer> c = i -> System.out.println(i);//Processa i escrevendo o seu valor no console
O tipo T define o tipo a ser processado
Não retorna informação (void)
Interface funcional: Function<T, R>
1
2
3
4
5
6
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
Function<String, Integer> f = s -> Integer.parseInt(s);//Transforma uma String em um int
O tipo T define o tipo de origem
O tipo R define o tipo de destino a ser retornado
Novas funcionalidades em coleções
- A Collections API ganhou novas funcionalidades para aproveitar o uso de expressões lambda
1
2
3
4
5
6
7
List<Integer> l = new ArrayList<>();
l.add(1);
l.add(2);
l.add(3);
l.forEach(item -> System.out.println(item));//Consumer<T>
l.removeIf(item -> item % 2 == 0);//Predicate<T>
Referências a métodos
- Permite converter métodos já existentes em expressões lambda
1
2
3
l.forEach(item -> System.out.println(item));
l.forEach(System.out::println);//Operador double colon (::)
Os parâmetros da expressão lambda são repassados para o método
Closures
Expressões lambda têm a capacidade de acessar variáveis definidas externamente
Este recurso é denominado closure
1
2
3
4
int mult = 2;//Variável definida fora da expressão lambda
Function<Integer, Integer> f = (x -> x * mult);
System.out.println(f.apply(5));
Variáveis externas acessadas por expressões lambda são implicitamente definidas como final
No caso da variável externa ser um atributo de classe, o final implícito não se aplica
O valor considerado é o do momento da execução
1
2
3
4
5
6
7
8
9
public class MyClass {
private int mult = 2;
public void executar() {
Function<Integer, Integer> f = (x -> x * mult);
mult = 5;
System.out.println(f.apply(5));//Imprime o valor 25
}
}