3

Expressão Lambda - Parte II (Quando e como usar)

 2 years ago
source link: https://dev.to/diariodeumacdf/expressao-lambda-parte-ii-quando-e-como-usar-efm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Parte II (Quando e como usar)

Parte 02 de 03 da documentação Oracle sobre Expressão Lambda :)

Um problema com classes anônimas é que se a implementação da sua classe anônima é muito simples sendo uma interface que contém um único método.

A partir disso, a sintaxe da classe anônima pode parecer incerta e não muito clara. Nesses casos, normalmente você está tentando passar funcionalidade como argumento para outro método, semelhante a iniciar uma ação quando alguém clica num botão.

As expressões lambdas te permitem fazer isso, trabalhar uma funcionalidade como argumento ou código como dado de informação.

No artigo anterior sobre Classe Anônima, mostramos como implementar uma classe sem a necessidade de se criar uma classe com um único método e implementar/extender outra classe para seguir com a construção da sua aplicação.

A expressão Lambda te permite fazer a mesma coisa, porém de uma forma mais conscisa ainda.

Caso de Uso Ideal para Expressão Lambda

Vamos supor que você está criando uma aplicação de rede social. Você quer criar uma feature que permite o administrador a realizar determinada ação, como, por exemplo, enviar uma mensagem para membros que satisfaçam determinada condição.

Cada pessoa nessa rede social é representada pela classe Pessoa:

public class Pessoa {
    public enum GENERO{
        MASCULINO, FEMININO
    }
    String nome;
    LocalDate nascimento;
    GENERO genero;
    String email;
    public int getIdade(){//...}    
    public void printPessoa(){//...}

}
Enter fullscreen modeExit fullscreen mode

Suponha que os membros dessa rede social estão armazenado numa List<Pessoa>

Passo 01: Criar métodos que encontrem membros que atendem a uma certa característica

Uma forma muito simples de fazer essa filtragem é criar um método para cada tipo de filtro que se precisa fazer, como para gênero ou idade.

Exemplo:

public static void printPessoasMaioresQue(List<Pessoa> relacao, int idade){
    for(Pessoa p : relacao){
        if(p.getIdade() >= age){
            p.printPessoa();
        }
    }
}
Enter fullscreen modeExit fullscreen mode

Esse método é muito frágil por conta da quantidade de atualizações que a aplicação ainda passará por conta de inclusão de novos membros.

Outro ponto, suponha que você atualizou a sua aplicação e alterou a estrutura da classe Pessoa que passa a conter mais variáveis, talvez isso impacte em todos os lugares em que você instanciou a classe de forma que o algoritmo que usa essa informação agora haja de forma diferente.

E, por fim, é um método restritivo, e se você precisar mostrar em tela usuários mais novo?

Passo 02: Criar métodos de busca mais generalizados

O método abaixo é mais generalizado do que o anterior:

public static void printPessoasComIdadeEntre(List<Pessoa> relacao, int menor, int maior){
    for(Pessoa p : relacao){
        if(menor <= p.getIdade() && p.getIdade() >= maior){
            p.printPessoa();
        }
    }
}
Enter fullscreen modeExit fullscreen mode

Mas e se você quiser mostrar em tela membros de determinado gênero ou a combinação de idade e gênero?

Ou se você quiser incluir atributos como status de relacionamento ou localização?

Apesar do método acima ser mais genérico do que o anterior, ter que criar um método para cada possibilidade de busca ainda deixa o código frágil.

Ao invés disso você pode separar as especificações de critério de busca do que você quer busca em classes separadas.

Passo 03: Especificar o código de critério de busca em uma classe local

O método abaixo mostra em tela membros que atendem determinado critério de busca que você especificar:

public static void printPessoas(List<Perssoa> relacao, VerificaPessoa criterio){
    for(Pessoa p: relacao){
        if(criterio.buscaPessoa(p)){
            p.printPessoa();
        }
    }
}
Enter fullscreen modeExit fullscreen mode

Esse método verifica cada Pessoa que consta na List relacao, se a pessoa atender o critério passado em criterio.buscaPessoa(p) então o método mostra em tela a pessoa.

Para especificar o critério de busca, você implementa uma interface chamada VerificaPessoa

interface VerificaPessoa{
    boolean buscaPessoa(Pessoa p);
}
Enter fullscreen modeExit fullscreen mode

A classe que fará uso desse método, faz a implementação da interface, exemplo:

class VerificaPessoaElegivelParaExercito implements VerificaPessoa{
    public boolean buscaPessoa(Pessoa p){
        return p.genero == Pessoa.Genero.MASCULINO && p.getIdade() >= 18 && p.get() <= 25;
    }
}
Enter fullscreen modeExit fullscreen mode

Para usar esse classe, você criar uma instância e invoca o printPessoa:

printPessoa(relacao, new VerificaPessoaElegivelParaExercito())
Enter fullscreen modeExit fullscreen mode

Apesar dessa estrutura ser menos frágil, você não precisa reescrever métodos se você alterar a classe Pessoa, você ainda tem código adicional: uma interface nova e uma classe local para cada busca que você pretende fazer na sua aplicação.

Passo 04: Especificar o critério de busca numa classe anônima

printPessoa(relacao, new VerificaPessoa(){
    public boolean buscaPessoa(Pessoa p){
        return p.genero == Pessoa.Genero.MASCULINO && p.getIdade() >= 18 && p.get() <= 25;
    }
})
Enter fullscreen modeExit fullscreen mode

Essa forma reduz a quantidade de linhas de código proque você não precisa criar uma nova classe cada busca que você precisa realizar.

Entretanto, a sintaxe de uma classe anônima é volumoso considerando que a interface VerificaPessoa só contém um método. Nesse caso, você pode usar uma expressão lambda ao invés da classe anônima.

Passo 05: Especificar o critério de busca numa expressão lambda

A interface VerificaPessoa é uma interface funcional. Uma classe funcional é aquela que contém apenas um método abstrato.

Exatamente por ela ser uma classe funcional que contém um único método abstrato, você pode omitir o nome do método quando você a implementa. Ao fazer isso, você estará implementando uma expressão lambda ao inveś de uma classe anônima.

printPessoa(relacao,(Pessoa p)-> p.genero == Pessoa.Genero.MASCULINO && p.getIdade() >= 18 && p.get() <= 25);
Enter fullscreen modeExit fullscreen mode

Você ainda pode usar uma interface funcional padrão no lugar de criar uma interface, o que ajuda a reduzir a criação de código.


interface Predicate<Pessoa>{
    boolean buscaPessoa(Pessoa p);  
}

public static void printPessoaComPredicate(List<Pessoa> relacao, Predicate<Pessoa> criterio){
    for(Pessoa p : relacao){
        if(criterio.buscaPessoa(p){
            p.printPessoa();
        }
    }
}

printPessoaComPredicate(relacao, p -> p.getGenero == Pessoa.Genero.MASCULINO && p.getIdade() >= 18 && p.getIdade() <= 25);
Enter fullscreen modeExit fullscreen mode

Fonte: Documentação Oracle


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK