Are Ltenatives for complex conditions in a lambda expression?

Asked

Viewed 515 times

7

With lambda expressions it is possible to filter elements from a collection of objects, creating a data stream according to the criterion passed in the expression for the method filter(), This guarantees you a way to manipulate the colletions.

It is also possible to specify more than one condition in the expression, see:

filter(pessoa -> pessoa.getIdade() >= 18 && pessoa.getGenero().equals("Feminino"))

In this case two conditions were passed, the first condition specifies people over 18 years and the second specifies gender (in this case, the female). However, what if I wanted to specify various conditions for example:

Obtain persons of legal age of the female sex whose letter name start with the letter M and live in the city of Campos do Jordão.

With various conditions it would be a little difficult to read the code and the condition would be very complex.

However, this is the only way I know to filter elements under various conditions. I would like to know if there is another way to do this, so that the code is not difficult to read, using lambda expressions.


Follow the example that illustrates the situation so that it can be reproduced.

Class Pessoa:

public class Pessoa 
{
    private String nome;
    private int idade;    
    private String genero;
    private String cidade;

    public Pessoa(String nome, int idade, String genrero, String cidade)
    {
        this.nome = nome;
        this.idade = idade;
        this.genero = genrero;                
        this.cidade = cidade;
    }

    public Pessoa()
    {

    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }        

    public String getGenero() {
        return genero;
    }

    public void setGenero(String genero) {
        this.genero = genero;
    }

    public String getCidade() {
        return cidade;
    }

    public void setCidade(String cidade) {
        this.cidade = cidade;
    }
}

Master code:

package lambdaexpressaoexemplo;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class LambdaExpressaoExemplo 
{
    public static void main(String[] args) 
    {
        List<Pessoa> pessoas = new ArrayList<>();
        pessoas.add(new Pessoa("Dener", 24, "Masculino", "Cruzeiro"));
        pessoas.add(new Pessoa("Janaina", 22, "Feminino", "Campos do Jordão"));
        pessoas.add(new Pessoa("Marciele", 17, "Feminino", "Campos do Jordão"));

        List<Pessoa> resultadoPesquisa = pessoas.stream().filter(pessoa -> pessoa.getIdade() >= 18 && pessoa.getGenero().equals("Feminino")).collect(Collectors.toList());
        resultadoPesquisa.forEach(p -> System.out.println(p.getNome()));

        System.out.println("\nQuantidade de mulheres acima de 18 anos: " + resultadoPesquisa.size());
    }    
}

2 answers

7


Yes, but it depends on the context.

In the case of filters, the type of expression required is of the Predicate<T>. Predicates are nothing more than a function that returns a boolean value.

You can compose predicates using functions and and or, for example.

Then you could have a collection of expressions common to your domain and compose expressions that fit the main business rules.

Example:

Predicate<Pessoa> maior = p -> p.getIdade() > 18;
Predicate<Pessoa> feminino = p -> p.getGenero().equals("Feminino");

And then the composition:

Predicate<Pessoa> filtroComTudoQueEuQuero = maior.and(feminino);

And finally, the filter:

List<Pessoa> resultadoPesquisa = pessoas.stream().filter(filtroComTudoQueEuQuero).collect(Collectors.toList());

In any case, something that helps is to format and indent the code in order to break the logic in one operation per line. That’s usually how I see it used:

    List<Pessoa> resultadoPesquisa = pessoas
            .stream()
            .filter(pessoa -> pessoa.getIdade() >= 18
                    && pessoa.getGenero().equals("Feminino"))
            .collect(Collectors.toList());

5

First, it is using only one condition expression. The fact that it has sub-expressions does not make it have multiple conditions. The condition remains unique.

It doesn’t seem hard to read. Do you think it would be easier if you were in one if, for example?

Well, some people won’t like that, but what I see is that you can simplify it by using a language that values simplified syntax. It would help a little bit.

What could simplify a little the use of lambda in itself, although this is questionable, is to create a method that takes the required parameter and calculates the result by returning to the lambda. Sincerely used to be unnecessary in most cases. Eventually you may have a gain moving around. Makes more sense if you’re using it in more than one place.

Another possibility is to have a method for each sub-expression. It has advantages and disadvantages.

Other than that, I don’t see how it could be easier to read:

List<Pessoa> resultadoPesquisa = pessoas.stream()
              .filter(pessoa ->
                  pessoa.getIdade() >= 18 &&
                  pessoa.getGenero().equals("Feminino"))
              .collect(Collectors.toList());

Using methods:

List<Pessoa> resultadoPesquisa = pessoas.stream()
              .filter(pessoa ->
                  ÉMaior(pessoa) &&
                  ÉFeminino(pessoa))
              .collect(Collectors.toList());

I put in the Github for future reference.

Some people think that moving the real expression to another place even hinders the readability, since to know what is really happening it is necessary to look elsewhere. Of course this depends a little on each case and the way it is being used.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.