简体   繁体   中英

Externally configurable filtering using Java lambdas

Lets say I have an external JSON as:

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

What this means is I want to check, in a list of Person objects for people with name as "jack" and age > 25 . It is fairly simple with Java 8 filtering(example shown is filtering just on name).

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

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 Person object which satisfy the criterion as a result.

That has little to do with streams per-se as far as I can tell. That filter method is just a Predicate which can be supplied 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);
}

Suppose you have another method:

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

Because Predicate.and , Predicate.or exists you could do:

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

thus chaining your predicates

There are two approaches to this.

Either you just chain call the desired filters inline:

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

Or, you have your own class implementing Predicate<Person> .

In which case, you may use a builder pattern to build your predicate step-by-step.

The difficulties you'll have to face are as follows:

  • Handling boolean relation between terms ( && vs || )
  • Handling nested boolean relations ( (a && b) || c is not a && (b || c) )

Note that Predicate has handy and and or methods to chain predicates.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM