恕我直言你可能真的不會java第3篇:Stream的Filter與謂詞邏輯

字母哥部落格發表於2020-06-18

file

一、基礎程式碼準備

建立一個實體類,該實體類有五個屬性。下面的程式碼使用了lombok的註解Data、AllArgsConstructor,這樣我們就不用寫get、set方法和全參建構函式了。lombok會幫助我們在編譯期生成這些模式化的程式碼。

@Data
@AllArgsConstructor
public class Employee {

   private Integer id;
   private Integer age;   //年齡
   private String gender;  //性別
   private String firstName;  
   private String lastName;
}

寫一個測試類,這個測試類的內容也很簡單,新建十個Employee 物件

public class StreamFilterPredicate {
    
    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);

    }

}

需要注意的是上面的filter傳入了lambda表示式(之前的章節我們已經講過了),表達過濾年齡大於70並且男性的Employee員工。輸出如下:

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

二、什麼是謂詞邏輯?

下面要說我們的重點了,通過之前的章節的講解,我們已經知道lambda表示式表達的是一個匿名介面函式的實現。那具體到Stream.filter()中,它表達的是什麼呢?看下圖:可以看出它表達的是一個Predicate介面,在英語中這個單詞的意思是:謂詞。
file

什麼是謂詞?(百度百科)

file

什麼是謂詞邏輯?

WHERE 和 AND 限定了主語employee是什麼,那麼WHERE和AND語句所代表的邏輯就是謂詞邏輯

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

三、謂詞邏輯的複用

通常情況下,filter函式中lambda表示式為一次性使用的謂詞邏輯。如果我們的謂詞邏輯需要被多處、多場景、多程式碼中使用,通常將它抽取出來單獨定義到它所限定的主語實體中。
比如:將下面的謂詞邏輯定義在Employee實體class中。

   public static Predicate<Employee> ageGreaterThan70 = x -> x.getAge() >70;
   public static Predicate<Employee> genderM = x -> x.getGender().equals("M");

3.1.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)]

3.2.or語法(交集)

List<Employee> filtered = employees.stream()
        .filter(Employee.ageGreaterThan70.or(Employee.genderM))
        .collect(Collectors.toList());

輸出如下:實際上就是年齡大於70的和所有的男性(由於79的那位也是男性,所以就是所有的男性)

[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)]

3.3.negate語法(取反)

List<Employee> filtered = employees.stream()
        .filter(Employee.ageGreaterThan70.or(Employee.genderM).negate())
        .collect(Collectors.toList());

輸出如下:把上一小節程式碼的結果取反,實際上就是所有的女性

[Employee(id=2, age=13, gender=F, firstName=Martina, lastName=Hengis), Employee(id=5, age=19, gender=F, firstName=Cristine, lastName=Maria), Employee(id=7, age=68, gender=F, firstName=Melissa, lastName=Roy), Employee(id=9, age=15, gender=F, firstName=Neetu, lastName=Singh)]

歡迎關注我的部落格,裡面有很多精品合集

  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格

覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。

相關文章