Predicate 是“断言”的意思。就是给你一段描述,判断这段描述是正确的还是错误的。这就像我们考试中做的判断题一样。
在编程中,我们经常会有这样的操作。当我们有一个集合,我们需要筛选出符合我们要求的一部分,抛弃不符合的那部分。
详细的例子就是,当我们拿到一份学成成绩单,我们需要获取那些60分以上的学生名单。
List scores = Arrays.asList(40, 55, 59 , 69, 80);
List passing = new ArrayList();
for (Integer score : scores) {
if (score >= 60) {
passing.add(score);
}
}
但是 Java 8 带来了 Lambda 表达式,我们现在完成这个功能只需要一行代码
List passing = scores.stream().filter((score) -> score >= 60).collect(Collectors.toList());
其中 filter 方法中接受的参数就是 Predicate
,Predicate
在 lambda 表达式中作为判断条件很是常用,下面我们来深入了解一下 Predicate
。
首先 Predicate
是一个函数式接口,这就意味着 Predicate
可以用一个 Lambda 表达式来表示。正如上面 filter() 方法传递的那样。
/**
* Returns a stream consisting of the elements of this stream that match
* the given predicate.
*
* This is an intermediate
* operation.
*
* @param predicate a non-interfering stateless predicate to apply to each element to determine if it
* should be included in the new returned stream.
* @return the new stream
*/
Stream filter(Predicate super T> predicate);
Streams 我们后面再介绍,这里我们可以把它当做是一个“集合”,我们可以对这个“集合”做某些操作。让我们看看一些例子。
在集合中使用 Predicate
定义一个 Employee
类
public class Employee {
public Employee(Integer id, Integer age, String gender, String fName, String lName){
this.id = id;
this.age = age;
this.gender = gender;
this.firstName = fName;
this.lastName = lName;
}
private Integer id;
private Integer age;
private String gender;
private String firstName;
private String lastName;
//Please generate Getter and Setters
@Override
public String toString() {
return this.id.toString()+" - "+this.age.toString(); //To change body of generated methods, choose Tools | Templates.
}
}
- 年龄大于21的男性员工
public static Predicate isAdultMale() {
return p -> p.getAge() > 21 && p.getGender().equalsIgnoreCase("M");
}
- 年龄大于 18 的女性员工
public static Predicate isAdultFemale() {
return p -> p.getAge() > 18 && p.getGender().equalsIgnoreCase("F");
}
- 年龄大于指定年龄的员工
public static Predicate isAgeMoreThan(Integer age) {
return p -> p.getAge() > age;
}
我们可以具体的过滤条件条件常见不同的 Predicate。
public class EmployeePredicates {
public static Predicate isAdultMale() {
return p -> p.getAge() > 21 && p.getGender().equalsIgnoreCase("M");
}
public static Predicate isAdultFemale() {
return p -> p.getAge() > 18 && p.getGender().equalsIgnoreCase("F");
}
public static Predicate isAgeMoreThan(Integer age) {
return p -> p.getAge() > age;
}
public static List filterEmployees (List employees, Predicate predicate) {
return employees.stream().filter( predicate ).collect(Collectors.toList());
}
}
这样使得我们的代码更加简洁
public class TestEmployeePredicates {
public static void main(String[] args){
Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
Employee e2 = new Employee(2,13,"F","Martina","Hengis");
Employee e3 = new Employee(3,43,"M","Ricky","Martin");
Employee e4 = new Employee(4,26,"M","Jon","Lowman");
Employee e5 = new Employee(5,19,"F","Cristine","Maria");
Employee e6 = new Employee(6,15,"M","David","Feezor");
Employee e7 = new Employee(7,68,"F","Melissa","Roy");
Employee e8 = new Employee(8,79,"M","Alex","Gussin");
Employee e9 = new Employee(9,15,"F","Neetu","Singh");
Employee e10 = new Employee(10,45,"M","Naveen","Jain");
List employees = new ArrayList();
employees.addAll(Arrays.asList(new Employee[]{e1,e2,e3,e4,e5,e6,e7,e8,e9,e10}));
System.out.println(filterEmployees(employees, isAdultMale()));
System.out.println(filterEmployees(employees, isAdultFemale()));
System.out.println(filterEmployees(employees, isAgeMoreThan(35)));
//Employees other than above collection of "isAgeMoreThan(35)" can be get using negate()
System.out.println(filterEmployees(employees, isAgeMoreThan(35).negate()));
}
}
Output:
[1 - 23, 3 - 43, 4 - 26, 8 - 79, 10 - 45]
[5 - 19, 7 - 68]
[3 - 43, 7 - 68, 8 - 79, 10 - 45]
[1 - 23, 2 - 13, 4 - 26, 5 - 19, 6 - 15, 9 - 15]
关于 Predicate 的一些思考
- Predicate 使得将一些条件(或者业务逻辑)统一到一个地方进行管理,方便单元测试
- 统一管理是的修改也更加方便了
- 可读性更强了,filterEmployees(employees, isAdultFemale()) 更容易理解,而且不再是 if-else 的代码块了