Reputation: 9
I would like to filter a list of object by multiple fields but these fields, which used for filtering can change. For example;
Assume that we have an Employee class with some properties:
@Data
public class Employee {
private Integer id;
private Integer age;
private String gender;
private String firstName;
private String lastName;
}
What is the best way to code a method that filter by sometimes age and gender or sometimes only firstName? (Samples can be reproduced, i.e. for this example it has 5 properties, so there are 5! = 120 possibilities) Could it be coded using lambda or something else in Java?
P.S. : Any possibilities are not predefined. Whatever comes from the request it should filter by it. I believe the example below will make this issue clear:
Assume that we have a Filter object with the same properties as Employee's. If age is given and the others are null, this service will filter only by age. Or only gender and firstName are given, it should get employees by the criteria.
Upvotes: 0
Views: 8055
Reputation: 16498
You can implement certain search functions for each attribute, such as
for the age the possible filters 'Equal'
, 'Greater than'
or 'Less than'
For the last name the filter 'is equal'
, 'begins with'
or 'ends with'.
'is male'
You could add something like below to your Employee class:
public static Predicate<Employee> ageEQ(int a) {
return e -> e.getAge() == a;
}
public static Predicate<Employee> ageGT(int a) {
return e -> e.getAge() > a;
}
public static Predicate<Employee> ageLT(int a) {
return e -> e.getAge() < a;
}
public static Predicate<Employee> isMale() {
return e -> e.getGender().equals("M");
}
public static Predicate<Employee> lastNameEQ(String name) {
return e -> e.getLastName().equals(name);
}
public static Predicate<Employee> lastNameStartsWith(String name) {
return e -> e.getLastName().startsWith(name);
}
And out a list of Employee:
List<Employee> list = new ArrayList<>();
list.add(new Employee(1,22,"M","Aaa","Bar"));
list.add(new Employee(2,33,"F","Ccc","Ddd"));
list.add(new Employee(3,44,"M","Eee","Fff"));
list.add(new Employee(4,55,"F","Ggg","Hhh"));
list.add(new Employee(5,66,"F","Mmm","Nnn"));
to filter for example all employees who are older than 40 and female:
list.stream()
.filter(Employee.ageGT(40).and(Employee.isMale().negate()))
.forEach(System.out::println);
Assuming your request is something like ?age>40&male=false ...
Upvotes: 1
Reputation: 2760
You probably want to use the filter
function. The way this function works is that, if your expression evaluates to true, it will return it to the resulting stream.
A sample snippet would be:
//Assuming employeeList is an ArrayList of Employee:
employeeList.stream().filter((e) -> e.age>25 && "M".equals(e.gender)); //Gives you a stream with all the male employees older than 25.
Here is some reading material for you! Specially the "2.3 For multiple condition." section.
Hope this helps!
Upvotes: 1
Reputation: 73538
If you know what you need to filter with, you can combine predicates.
Let's say you want to filter Employees with a first name starting with J
, that are over 37 years old.
Predicate<Employee> p = e -> e.getFirstName().startsWith("J");
p = p.and(e -> e.getAge() > 37);
You can now use predicate p
in the filter. You just need to build the final predicate depending on the conditions required.
Upvotes: 0