如何用Java Streams基于动态条件列表过滤Employee集合?
问题描述
我有一个包含Employee对象列表的Person类实例,Employee具备name、age、dept、city属性。另有一个动态的Criteria列表,可包含1个或多个条件。需要基于此列表过滤Employee列表:当条件类型为AGE时对比emp.age;类型为CITY时对比emp.city,其他类型同理匹配对应属性。相关类定义如下(需补全getter/setter以支持Stream操作):
public class Person { private List<Employee> empList; public Person(List<Employee> empList) { super(); this.empList = empList; } public List<Employee> getEmpList() { return empList; } public void setEmpList(List<Employee> empList) { this.empList = empList; } }
public class Employee { private String name; private int age; private String city; private String dept; public Employee(String name, int age, String city, String dept) { super(); this.name = name; this.age = age; this.city = city; this.dept = dept; } // 补全getter方法 public String getName() { return name; } public int getAge() { return age; } public String getCity() { return city; } public String getDept() { return dept; } }
public class Criteria { private CriteriaType type; private String value; public Criteria(CriteriaType type, String value) { super(); this.type = type; this.value = value; } // 补全getter方法 public CriteriaType getType() { return type; } public String getValue() { return value; } }
public enum CriteriaType { NAME, CITY, AGE, DEPT }
public class FilterEmployee { public static void main(String[] args) { Employee emp1 = new Employee("John", 30, "Dallas", "HR"); Employee emp2 = new Employee("Steve", 31, "Austin", "HR"); Employee emp3 = new Employee("Andrew", 25, "Houston", "Finance"); Employee emp4 = new Employee("Mike", 30, "Dallas", "HR"); List<Employee> empList = new ArrayList<>(); empList.add(emp1); empList.add(emp2); empList.add(emp3); empList.add(emp4); Person personObj = new Person(empList); Criteria c1 = new Criteria(CriteriaType.CITY, "Dallas"); Criteria c2 = new Criteria(CriteriaType.NAME, "Mike"); List<Criteria> criteriaList = new ArrayList<>(); criteriaList.add(c1); criteriaList.add(c2); // 需基于Criteria列表过滤包含Employee列表的Person对象 } }
请问是否存在简洁的方式,使用Java Streams完成该条件对比与过滤操作?
解决方案:Java Streams动态条件过滤
可以用Java Streams结合Predicate简洁实现动态条件过滤,核心是将每个Criteria转换为对应的断言,再组合所有断言进行过滤。
实现步骤
- 转换单个Criteria为Predicate:根据
CriteriaType的不同,创建对应的Predicate<Employee>,匹配Employee的对应属性。注意AGE类型需要将字符串值转为整数再对比。 - 组合所有Predicate:将多个条件用
Predicate.and()组合,确保只有满足所有条件的Employee才会被保留。 - Stream过滤:从
Person实例中获取员工列表,通过Stream的filter方法应用组合后的断言,最后收集结果。
完整代码实现
修改FilterEmployee的main方法,添加过滤逻辑:
import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; public class FilterEmployee { public static void main(String[] args) { Employee emp1 = new Employee("John", 30, "Dallas", "HR"); Employee emp2 = new Employee("Steve", 31, "Austin", "HR"); Employee emp3 = new Employee("Andrew", 25, "Houston", "Finance"); Employee emp4 = new Employee("Mike", 30, "Dallas", "HR"); List<Employee> empList = new ArrayList<>(); empList.add(emp1); empList.add(emp2); empList.add(emp3); empList.add(emp4); Person personObj = new Person(empList); Criteria c1 = new Criteria(CriteriaType.CITY, "Dallas"); Criteria c2 = new Criteria(CriteriaType.NAME, "Mike"); List<Criteria> criteriaList = new ArrayList<>(); criteriaList.add(c1); criteriaList.add(c2); // 1. 将每个Criteria转换为Predicate List<Predicate<Employee>> predicates = criteriaList.stream() .map(criteria -> { switch (criteria.getType()) { case NAME: return emp -> emp.getName().equals(criteria.getValue()); case CITY: return emp -> emp.getCity().equals(criteria.getValue()); case AGE: return emp -> emp.getAge() == Integer.parseInt(criteria.getValue()); case DEPT: return emp -> emp.getDept().equals(criteria.getValue()); default: return emp -> true; // 默认匹配所有 } }) .collect(Collectors.toList()); // 2. 组合所有Predicate:所有条件必须同时满足 Predicate<Employee> combinedPredicate = predicates.stream() .reduce(Predicate::and) .orElse(emp -> true); // 如果没有条件,返回所有员工 // 3. 过滤员工列表 List<Employee> filteredEmps = personObj.getEmpList().stream() .filter(combinedPredicate) .collect(Collectors.toList()); // 测试输出:应该只输出Mike filteredEmps.forEach(emp -> System.out.println(emp.getName())); } }
说明
- 若需要支持或条件,只需将
Predicate::and替换为Predicate::or即可; - 对于
AGE类型的条件,要确保传入的value是合法整数,否则会抛出NumberFormatException,可以根据需求添加异常处理; - 补全getter是因为Stream操作需要访问Employee和Criteria的私有属性,这是Java封装性的要求。
内容的提问来源于stack exchange,提问作者Soni
相关产品推荐
相关产品推荐

