Lucent's Blog

华发寻春喜见梅,一株临路雪倍堆。



代码在写我

Bug在De我

螃蟹在剥我的壳

漫天的我落在雪花上

而你在想我...

6LCi5Y2O5qKF

Stream的filter与谓语逻辑

什么是谓语逻辑

如下代码中WHERE 和 AND 限定了主语employee是什么,那么WHERE和AND语句所代表的逻辑就是谓语逻辑。

SELECT *
FROM employee
WHERE age > 70
AND gender = 'M'

lambda表达式表达的是一个匿名接口函数的实现,那具体到Stream.filter()中,它表达的是一个Predicate接口,在英语中这个单词的意思是:谓语。
Snipaste_20200624_105436.png

创建一个实体类Employee

下面的代码使用了lombok的注解Data、AllArgsConstructor来代替getter,setter和全参构造方法

@Data
@AllArgsConstructor
public class Employee {
   private Integer id;
   private Integer age;
   /**
   *性别,F女,M男
   */
   private String gender;
   private String firstName;  
   private String lastName;
}

测试

创建十个Employee对象,并筛选出年龄大于70的男性

public class test{
    
    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<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);

        List<Employee> filtered = employees.stream()
                .filter(e -> e.getAge() > 70 && e.getGender().equals("M"))
                .collect(Collectors.toList());

        System.out.println(filtered);

    }

}

结果如下:

[Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin)]

以上代码中filter限制了集合filtered中的内容,所以filter中的语句是谓语,其逻辑就是谓语逻辑。

谓语逻辑的复用

通常情况下,filter函数中lambda表达式为一次性使用的谓词逻辑。如果我们的谓词逻辑需要被多处、多场景、多代码中使用,通常将它抽取出来单独定义到它所限定的主语实体中。
比如:将下面的谓词逻辑定义在Employee实体class中。

   /**
   *年龄大于70
   */
   public static Predicate<Employee> ageGreaterThan70 = x -> x.getAge() >70;
  /**
   *性别为男
   */ 
   public static Predicate<Employee> genderM = x -> x.getGender().equals("M");

结果:

 @Data
    @AllArgsConstructor
    public static class Employee {

        private Integer id;
        private Integer age;   //年龄
        private String gender;  //性别
        private String firstName;
        private String lastName;
	/**
   	*年龄大于70
   	*/
        public static Predicate<Employee> ageGreaterThan70 = x -> x.getAge() >70;
	/**
   	*性别为男
   	*/ 
        public static Predicate<Employee> genderM = x -> x.getGender().equals("M");
    }
  • and语法(并集&&)
List<Employee> filtered = employees.stream()
        .filter(Employee.ageGreaterThan70.and(Employee.genderM))
        .collect(Collectors.toList());

结果:

[Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin)]
  • or语法(交集||)
List<Employee> filtered = employees.stream()
        .filter(Employee.ageGreaterThan70.or(Employee.genderM))
        .collect(Collectors.toList());

结果:

[Employee(id=1, age=23, gender=M, firstName=Rick, lastName=Beethovan), Employee(id=3, age=43, gender=M, firstName=Ricky, lastName=Martin), Employee(id=4, age=26, gender=M, firstName=Jon, lastName=Lowman), Employee(id=6, age=15, gender=M, firstName=David, lastName=Feezor), Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin), Employee(id=10, age=45, gender=M, firstName=Naveen, lastName=Jain)]
  • negate语法(取反)
List<Employee> filtered = employees.stream()
	.filter(Employee.ageGreaterThan70
	.and(Employee.genderM).negate()
	.collect(Collectors.toList());

结果:

[test.Employee(id=1, age=23, gender=M, firstName=Rick, lastName=Beethovan), test.Employee(id=2, age=13, gender=F, firstName=Martina, lastName=Hengis), test.Employee(id=3, age=43, gender=M, firstName=Ricky, lastName=Martin), test.Employee(id=4, age=26, gender=M, firstName=Jon, lastName=Lowman), test.Employee(id=5, age=19, gender=F, firstName=Cristine, lastName=Maria), test.Employee(id=6, age=15, gender=M, firstName=David, lastName=Feezor), test.Employee(id=7, age=68, gender=F, firstName=Melissa, lastName=Roy), test.Employee(id=9, age=15, gender=F, firstName=Neetu, lastName=Singh), test.Employee(id=10, age=45, gender=M, firstName=Naveen, lastName=Jain)]
最近的文章

Stream管道流的map操作

Stream管道流map的基础用法将集合中的每一个字符串,全部转换成大写:List<String>alpha=Arrays.asList("Monkey","Lion","Giraffe","Lemur");…

继续阅读
更早的文章

Stream API代替for循环

什么是StreamAPIJavaStream函数式编程接口最初是在Java8中引入的,并且与lambda一起成为Java开发的里程碑式的功能特性,它极大的方便了开放人员处理集合类数据的效率。JavaStream就是一个数据流经的管道,并且在管道中对数据进行操作,然后流入下一个管道。…

继续阅读