Configurable external filtering using Java lambdas

Suppose I have external JSON:

[{
    "condition": "equals",
    "field": "name",
    "value": "jack"
  },
  {
    "condition": "greater",
    "field": "age",
    "value": 25
  }
]

      

What this means, I want to check in the list of Person objects for people named "jack"

and age > 25

. It's pretty easy with Java 8 filtering (example shown as filtering by name only).

However, I want this filter to be customizable and also to apply multiple filters. Assuming the Person pojo below (which is self-evident) accepts a name and age, how can I make the filters dynamic or customizable?

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Accessors and Mutators
}

      

List<Person> persons = Arrays.asList(
    new Person("mkyong", 30),
    new Person("jack", 20),
    new Person("lawrence", 40)
);

Person result1 = persons.stream()            // Convert to steam
    .filter(x -> "jack".equals(x.getName())) // we want "jack" only
    .findAny()                               // If 'findAny' then return found
    .orElse(null);  

      

I am expecting a list of a Person object that ultimately satisfies the criterion.

+3


source to share


2 answers


It has nothing to do with streams

per se as far as I can tell. This filtering method is just Predicate

one that can be provided as an instance, for example from a factory method that you could create.

static Predicate<Person> fromName(String value){
    return p -> p.getName().equals(value);
}

      

Let's assume you have another method:

static Predicate<Person> fromAge(int value) {
    return p -> p.getAge() == value;
}

      



Since Predicate.and

, Predicate.or

exists, you can do:

 fromAge(12).and(fromName("jack"));

      

thus linking your predicates

+5


source


There are two approaches to this.

Or, you just chain the required filters inline:

Person result1 = persons.stream()
    .filter(x -> "jack".equals(x.getName()))
    .filter(x -> 25 > x.getAge()) // new filter
    .findAny()
    .orElse(null);

      

Or do you have your own class that implements Predicate<Person>

.



In this case, you can use the builder pattern to build the predicate step by step.

The difficulties you will have to face are as follows:

  • Handling boolean relations between terms ( &&

    vs ||

    )
  • Handling nested boolean relations ( (a && b) || c

    not a && (b || c)

    )

Please note that Predicate

is convenient methods and

and or

chain predicates.

+2


source







All Articles