Primeiramente Expressões Lambda são funções anônimas, a diferença de uma função normal é que elas não possui nome então eles acaba sendo definidas diretamente muitas vezes em uma única linha, e serve para fornecer abstrações para problemas complexos e isso acaba limpando o código deixando o escopo menor.
Elas estão presentes nas linguagens como Java, C#, Python, Ruby e entre outras do mercado.
As principais vantagens sobre a utilização da expressão lambda:
- Código mais simples;
- Simplificar diversas operações em cima de uma coleção de dados;
- Possui uma sintaxe extremamente simples.
E as poucas desvantagens:
- Funções anônimas podem gerar problemas na hora de depurar o código;
- Muitos argumentos em uma Expressão Lambda gera legibilidade mais difícil;
Agora vou mostrar alguns exemplos de uso de expressão lambda, utilizarei a linguagens Java para dar os exemplos.
package teste;
import java.util.ArrayList;
import java.util.Collection;
public class Funcionario {
public String nome;
public double salario;
public Funcionario chamado(String nome){
this.nome = nome;
return this;
}
public Funcionario comSalario(double salario){
this.salario = salario;
return this;
}
public static void main(String[] args) {
Collection<Funcionario> funcionarios = new ArrayList<Funcionario>();
Funcionario joao = new Funcionario().chamado("João").comSalario(2000.00);
Funcionario pedro = new Funcionario().chamado("Pedro").comSalario(3000.00);
funcionarios.add(joao);
funcionarios.add(pedro);
for (Funcionario f : funcionarios) {
System.out.println(f.nome + ": " + f.salario);
}
funcionarios.forEach((Funcionario f) -> System.out.println(f.nome + ": " + f.salario));
}
}
Linhas 29 até 33: Usamos for para iterar os índices do ArrayList funcionarios
Linha 35: A partir do Java 8 podemos utilizar o método forEach
da interface Iterable
, da qual herda a classe ArrayList
, para iterar os índices de uma coleção. Esse método recebe como parâmetro a interface funcional Consumer
, que possui o método abstrato accept
. Ao passarmos para o método forEach
essa expressão lambda, estamos declarando que o método accept
deve ser chamado, recebendo como parâmetro a instância de Funcionario
f e realizando a impressão do nome e salário de cada funcionário. O método forEach
se encarregará de executar essa ação repetidas vezes, enquanto existirem itens no ArrayList
.
A seguir mostrarei como criar uma interface funcional, Condicao
que contém o método test.
package teste;
public interface Condicao<T> {
boolean teste(T t);
}
Linhas 3 até 7: Declaramos a interface funcional genérica Condicao
. O uso de Generics
na declaração desta interface nos permite informar um tipo genérico para o método teste
.
Linha 5: Aqui temos o método abstrato teste
que recebe T
, um tipo genérico, e retorna um boolean
.
Usaremos essa interface no método getFuncionarios
, da classe FolhaDePagamento
, para filtrar os funcionários a partir de uma condição.
package teste;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class FolhaDePagamento {
public List<Funcionario> getFuncionarios(Condicao<Funcionario> condicao) {
Collection<Funcionario> funcionarios = new ArrayList();
Funcionario joao = new Funcionario().chamado("João").comSalario(2000.00);
Funcionario pedro = new Funcionario().chamado("Pedro").comSalario(3000.00);
funcionarios.add(joao);
funcionarios.add(pedro);
List<Funcionario> funcionariosComCondicao = new ArrayList<>();
funcionarios.forEach(f -> {
if (condicao.teste(f)){
funcionariosComCondicao.add(f);
}
});
return funcionariosComCondicao;
}
}
Linhas 7 até 27: Declaramos a classe FolhaDePagamento
, que contém o método getFuncionarios
. Esse método retornará uma lista de funcionários selecionados a partir de uma condição.
Linhas 9 e 15: Criamos uma lista com alguns funcionários que usaremos como base. Em um exemplo mais próximo do mundo real essa lista poderia vir de um banco de dados. Logo após está a lista funcionariosComCondicao
, que vai armazenar os funcionários que atendem a condição especificada.
Linha 19: Aqui usamos uma expressão lambda para receber cada funcionário da lista funcionários, submetendo-os ao método Condicao.teste
. Se esse método retornar true, o funcionário é adicionado na lista funcionariosComCondicao
.
Linha 25: Retornamos a lista dos funcionários que atendem a condição.
Na interface Condicao
o teste
é um método abstrato, que não possui corpo. O que de fato esse método faz será implementado por alguma classe que herde de Condicao
ou, como veremos a seguir, por uma expressão lambda.
public static void main(String[] args) {
FolhaDePagamento folhaDePagamento = new FolhaDePagamento();
List<Funcionario> funcionarios = folhaDePagamento.getFuncionarios(
f -> f.salario <= 2500.00F);
funcionarios.forEach(f -> System.out.println(f.nome));
}
Linha 30: Invocamos o método getFuncionarios
atribuindo seu retorno a lista funcionarios
.
Linha 31: Usamos uma expressão lambda para invocar o método teste
da classe Condicao
. Como parâmetro passamos um objeto do tipo funcionário, e como corpo criamos uma expressão lógica, que retorna true ou false.
Linha 33: Percorremos os itens do ArrayList
que contém os funcionários retornados por getFuncionarios
, aqueles com salários menores ou iguais a 2500.00F
, imprimindo seus nomes.
Com o Java 8, além do suporte as expressões lambda, foi introduzida a API Streams, que simplifica a realização de tarefas comuns relacionadas a coleções. No exemplo abaixo usamos algumas das funções da classe Stream, do pacote java.util.stream,
para filtrar um grupo de funcionários, utilizando para isso uma condição, e retornar uma lista contendo seus nomes.
public static void main(String[] args) {
FolhaDePagamento folhaDePagamento = new FolhaDePagamento();
List<Funcionario> funcionarios = folhaDePagamento.getFuncionarios(
f -> f.salario <= 2500.00F);
funcionarios.forEach(f -> System.out.println(f.nome));
List<String> nomeFuncionarios = funcionarios.stream()
.filter(f -> f.salario > 2500.00F)
.map(f -> f.nome)
.collect(Collectors.toList());
}
}
Linha 36: Usamos o método stream para retornar um objeto do tipo Stream a partir da lista de funcionários. Assim poderemos acessar os métodos da classe Stream.
Linha 37: Com o método filter filtramos os funcionários que atendem a condição salário > 2500.00F
, usando para isso uma expressão lambda.
Linha 38: Declaramos para o método map
, a partir de uma expressão lambda, que usaremos o nome de cada funcionário para preencher a lista de retorno.
Linha 39: Retornamos a lista de nomes com o método collect
. A transformação desse retorno em uma lista é facilitada pelo método toList
da classe Collectors
.
Espero que esses exemplos tenha esclarecido suas duvidas sobre o que é expressões lambda, e por favor se tiver alguma sugestão de como fazer melhor estou aberto a ouvi-lo pois estou aprendendo ainda e toda ajuda é bem vinda =).