Are there altematives for complex conditions in a lambda expression?

7

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

You can also 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 persons over the age of 18 and the second specifies the gender (in this case, the female). However, what if I wanted to specify several conditions for example:

  

Obtain the female overage whose letter of the   name begins with the letter M and that lives in the city of Campos do Jordão.

With several 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 of filtering elements with various conditions. I would like to know if there is another way to do this, in a way that the code is not difficult to read, using lambda expressions.

The example below illustrates the situation so it can be played.

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;
    }
}

Primary 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());
    }    
}
    
asked by anonymous 29.02.2016 / 04:54

2 answers

7

Yes, but it depends on context.

In the case of filters, the type of expression required is of type 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.

So 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 so as to break the logic in one operation per line. Usually this is how I see it being used:

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

First, you are using only one condition expression. The fact that it has subexpressions does not have several conditions. The condition remains unique.

It does not seem difficult to read. Do you think it would be easier if you were in if , for example?

Well, some people will not like this, but what I see that simplifies is to use a language that praises by simplified syntax. It would help a little.

What could simplify the use of lambda itself, although this is questionable, is to create a method that receives the required parameter and compute the result by returning to lambda in>. Honestly it's usually unnecessary in most cases. Eventually you may have a gain shifting location. It makes more sense to use 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 do not see how it could be easier to read than organizing better:

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());

Some people think that shifting the real expression to another place even disables 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.

    
29.02.2016 / 06:11