我有一个Employee
类,有一个方法getEmployees()
返回所有可能的员工。我想在相同的时候添加多个过滤条件以及不同的and
条件,只有当传入的参数是not null
时。
我尝试过以下方法来进行过滤部分,但是如果链接正在发生,则有多个if-else。有没有更好的方法来减少这种链接到单个谓词类似在dynamic filtering做的事情。我的链接代码如下:
员工班
public class Employee{
private String fName;
private String lName;
private String type;
//getters & setters
}
if-else if chaining block:
public List<Employee> retrieveEmployees(String searchToken, String fName, String lName, String type){
//this will retrieve all the available employees
List<Employee> employees = getEmployees();
List<Employee> filteredEmployees= new ArrayList<>();
//perform filtering on the basis of accepted params
if(searchToken !=null){
filteredEmployees=employees
.stream()
.filter(emp-> emp.getFName().equalsIgnoreCase(searchToken) && emp.getLName().equalsIgnoreCase(searchToken))
.collect(Collectors.toList());
}
else if (fName != null && lName != null && type != null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getFName().equalsIgnoreCase(fName) && emp.getLName().equalsIgnoreCase(lName) && emp.getType().equalsIgnoreCase(type))
.collect(Collectors.toList());
} else if (type != null && fname != null && lname == null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getFName().equalsIgnoreCase(fName) && emp.getType().equalsIgnoreCase(type))
.collect(Collectors.toList());
} else if (fname != null && lname != null && type == null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getFName().equalsIgnoreCase(fName) && emp.getLName().equalsIgnoreCase(lName))
.collect(Collectors.toList());
} else if (lname != null && type != null && fname == null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getLName().equalsIgnoreCase(lName) && emp.getType().equalsIgnoreCase(type))
.collect(Collectors.toList());
} else if (fname != null && lname == null && type == null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getFName().equalsIgnoreCase(fName))
.collect(Collectors.toList());
} else if (lname != null && fname == null && type == null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getLName().equalsIgnoreCase(lName))
.collect(Collectors.toList());
} else if (type != null && fname == null && lname == null) {
filteredEmployees=employees
.stream()
.filter(emp-> emp.getType().equalsIgnoreCase(type))
.collect(Collectors.toList());
} else {
filteredEmployees=getEmployees();
}
return filteredEmployees;
}
我尝试了类似的东西,但它失败了,因为谓词本身只是做or/and
它不满足我在if-else if
块中所做的:
List<Predicate<Employee>> predicates=Arrays.asList(
e -> e.getFName().equalsIgnoreCase(fName),
e -> e.getLName().equalsIgnoreCase(lName),
e -> e.getType().equals(type)
);
Predicate<Employee> compositePredicate = predicates
.stream()
.reduce(w -> true, Predicate::or); //tried with 'and' as well
filteredEmployees= employees
.stream()
.filter(compositePredicate)
.collect(Collectors.toList());
我缺少什么?什么是有效的流谓词链接方法可以应用?
你可以有一个类SearchFilter
,它将包含所有的过滤字段,如searchToken
,fname
等,另一个Condition
,如:
class Condition {
private Predicate<SearchFilter> searchFilterPredicate;
private Function<SearchFilter, Predicate<Employee>> function;
}
然后你可以定义一个包含所有条件的静态不可变列表:
List<Condition> conditions = Arrays.asList(
new Condition(sf -> sf.getSearchToken() != null,
sf -> emp -> emp.getFName().equalsIgnoreCase(sf.getSearchToken()) && emp.getLName().equalsIgnoreCase(sf.getSearchToken())),
new Condition(sf -> ObjectUtils.allNotNull(sf.getFname(), sf.getLname(), sf.getType()),
sf -> emp-> emp.getFName().equalsIgnoreCase(sf.getFname()) && emp.getLName().equalsIgnoreCase(sf.getLname()) && emp.getType().equalsIgnoreCase(sf.getType()))
//...
);
最后是retrieveEmployees
方法
public List<Employee> retrieveEmployees(String searchToken, String fname, String lname, String type){
List<Employee> employees = getEmployees();
SearchFilter searchFilter = new SearchFilter(searchToken, fname, lname, type);
Optional<Predicate<Employee>> firstCondition = conditions.stream()
.filter(condition -> condition.getSearchFilterPredicate().test(searchFilter))
.findFirst()
.map(condition -> condition.getFunction().apply(searchFilter));
return firstCondition.map(employeePredicate -> employees.stream()
.filter(employeePredicate)
.collect(Collectors.toList()))
.orElse(employees);
}
另一种解决方案可能是检查每个过滤器字段并将其添加到谓词
List<Employee> retrieveEmployees(String searchToken, String fname, String lname, String type){
List<Employee> employees = getEmployees();
if(searchToken != null) {
return employees
.stream()
.filter(emp -> emp.getFName().equalsIgnoreCase(searchToken) && emp.getLName().equalsIgnoreCase(searchToken))
.collect(Collectors.toList());
}
Predicate<Employee> predicate = employee -> true;
if(type != null) {
predicate = predicate.and(emp -> emp.getType().equalsIgnoreCase(type));
}
if(lname != null) {
predicate = predicate.and(emp -> emp.getLName().equalsIgnoreCase(lname));
}
if(fname != null) {
predicate = predicate.and(emp -> emp.getFName().equalsIgnoreCase(fname));
}
return employees.stream()
.filter(predicate)
.collect(Collectors.toList());
}