Predicate trong Java 8

1. Giới thiệu Predicate<T>

Trong Java 8, Predicate<T> là một functional interface và do đó nó có thể được sử dụng với lambda expression hoặc method reference cho một mục đích cụ thể nào đó. Predicate<T> sẽ trả về giá trị true/false của một tham số kiểu T mà bạn đưa vào có thỏa với điều kiện của Predicate đó hay không, cụ thể là điều kiện được viết trong phương thức test().

Interface Predicate được khai báo trong package java.util.function như sau:

Trong đó:

  • boolean test(T t) : là một phương thức trừu tượng có thể được sử dụng với lambda expression hoặc method reference cho một mục đích cụ thể nào đó.
  • Phương thức test() trả về true nếu đối số đầu vào khớp với biến predicate (điều kiện kiểm tra), nếu không trả về false.

Một số phương thức mặc định (default method) trong lớp Interface Predicate:

  • and() : Nó thực hiện logic AND của predicate mà nó được gọi với một biến predicate khác. Ví dụ: predicate1.and (predicate2).
  • or() : Nó thực hiện logic OR của predicate mà nó được gọi với một biến predicate khác. Ví dụ: predicate1.or(predicate2).
  • negate() : Nó thực hiện phủ định kết quả của biến predicate được gọi. Ví dụ: predicate1.negate().

Ngoài ra interface Predicate còn có một phương thức tĩnh (static method) là isEqual(). Phương thức này được sử dụng để kiểm tra hai đối có số bằng nhau theo Objects.equals (Object, Object).

2. Một số ví dụ

2.1. Sử dụng test()

package com.maixuanviet.predicate;
 
import java.util.function.Predicate;
 
public class PredicateExample1 {
 
    public static void main(String[] args) {
 
        // Predicate String
        Predicate<String> predicateString = s -> {
            return s.equals("maixuanviet");
        };
        System.out.println(predicateString.test("maixuanviet")); // true
        System.out.println(predicateString.test("GP Coder")); // false
 
        // Predicate integer
        Predicate<Integer> predicateInt = i -> {
            return i > 0;
        };
        System.out.println(predicateInt.test(1)); // true
        System.out.println(predicateInt.test(-1)); // false
    }
}

2.2. Sử dụng and(), or(), negate(), isEqual()

package com.maixuanviet.predicate;
 
import java.util.function.Predicate;
 
public class PredicateExample2 {
 
    public static void main(String[] args) {
 
        Predicate<String> predicate = s -> {
            return s.equals("maixuanviet");
        };
 
        // AND logical operation
        Predicate<String> predicateAnd = predicate.and(s -> s.length() == 11);
        System.out.println(predicateAnd.test("maixuanviet.com")); // true
 
        // OR logical operation
        Predicate<String> predicateOr = predicate.or(s -> s.length() == 11);
        System.out.println(predicateOr.test("maixuanviet.com")); // true
 
        // NEGATE logical operation
        Predicate<String> predicateNegate = predicate.negate();
        System.out.println(predicateNegate.test("maixuanviet")); // false
    }
}

2.3. Kết hợp nhiều Predicate

package com.maixuanviet.predicate;
 
import java.util.function.Predicate;
 
public class PredicateExample3 {
 
    public static void main(String[] args) {
 
        // Creating predicate
        Predicate<Integer> greaterThanTen = (i) -> i > 10;
        Predicate<Integer> lessThanTwenty = (i) -> i < 20;
 
        // Calling Predicate Chaining
        boolean result = greaterThanTen.and(lessThanTwenty).test(15);
        System.out.println(result); // true
 
        // Calling Predicate method
        boolean result2 = greaterThanTen.and(lessThanTwenty).negate().test(15);
        System.out.println(result2); // false
    }
}
&#91;/code&#93;
<!-- /wp:shortcode -->

<!-- wp:heading {"level":3} -->
<h3>2.4. Sử dụng Predicate vơi Collection</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Ví dụ chúng ta có thông tin Employee bao gồm các thông tin id, tên, tuổi, giới tính, … như bên dưới:</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->

package com.maixuanviet.predicate;
 
public class Employee {
 
    private Integer id;
    private Integer age;
    private String gender;
    private String firstName;
    private String lastName;
 
    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;
    }
 
    @Override
    public String toString() {
        return this.id.toString() + " - " + this.age.toString();
    }
 
    // Please generate Getter and Setters
}

Bây giờ chúng ta sẽ xây dựng các Predicate để thực thi như sau:

package com.maixuanviet.predicate;
 
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
 
public class EmployeePredicates {
 
    // Tất cả Employee có tuổi > 21 và có giới tính là Male
    public static Predicate<Employee> isAdultMale() {
        return p -> p.getAge() > 21 && p.getGender().equalsIgnoreCase("M");
    }
 
    // Tất cả Employee có tuổi > 18 và có giới tính là Female
    public static Predicate<Employee> isAdultFemale() {
        return p -> p.getAge() > 18 && p.getGender().equalsIgnoreCase("F");
    }
 
    // Tất cả Employee lớn hơn số tuổi được truyền vào
    public static Predicate<Employee> isAgeMoreThan(Integer age) {
        return p -> p.getAge() > age;
    }
 
    // Lấy danh sách Employee thõa mãn predicate được truyền vào
    public static List<Employee> filterEmployees( //
            List<Employee> employees, Predicate<Employee> predicate) {
        return employees.stream().filter(predicate).collect(Collectors.<Employee>toList());
    }
}

Chúng ta sẽ bắt đầu apply các Predicate này như sau:

package com.maixuanviet.predicate;
 
import static com.maixuanviet.predicate.EmployeePredicates.filterEmployees;
import static com.maixuanviet.predicate.EmployeePredicates.isAdultFemale;
import static com.maixuanviet.predicate.EmployeePredicates.isAdultMale;
import static com.maixuanviet.predicate.EmployeePredicates.isAgeMoreThan;
 
import java.util.Arrays;
import java.util.List;
 
public class EmployeePredicatesTest {
 
    public static void main(String[] args) {
 
        List<Employee> employees = Arrays.asList( //
                new Employee(1, 23, "M", "Rick", "Beethovan"), //
                new Employee(2, 13, "F", "Martina", "Hengis"), //
                new Employee(3, 43, "M", "Ricky", "Martin"), //
                new Employee(4, 26, "M", "Jon", "Lowman"), //
                new Employee(5, 19, "F", "Cristine", "Maria"), //
                new Employee(6, 15, "M", "David", "Feezor"), //
                new Employee(7, 68, "F", "Melissa", "Roy"), //
                new Employee(8, 79, "M", "Alex", "Gussin"), //
                new Employee(9, 15, "F", "Neetu", "Singh"), //
                new Employee(10, 45, "M", "Naveen", "Jain") //
        );
 
        // Lấy danh sách Employee nam 21+
        System.out.println(filterEmployees(employees, isAdultMale()));
 
        // Lấy danh sách Employee nữ 18+
        System.out.println(filterEmployees(employees, isAdultFemale()));
 
        // Lấy danh sách Employee > 35 tuổi
        System.out.println(filterEmployees(employees, isAgeMoreThan(35)));
 
        // Lấy danh sách Employee <= 35 tuổi
        System.out.println(filterEmployees(employees, isAgeMoreThan(35).negate()));
    }
}
&#91;/code&#93;
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>Output của chương trình trên như sau:</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->

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

2.5. Sử dụng Predicate với các lớp cho kiểu dữ liệu nguyên thủy (primitive type)

Java 8 cung cấp một số Interface Predicate cho các wrapper class của kiểu dữ liệu nguyên thủy như sau:

  • IntPredicate : chấp nhận một giá trị kiểu Int duy nhất.
  • LongPredicate : chấp nhận một giá trị kiểu Long duy nhất.
  • DoublePredicate : chấp nhận một giá trị kiểu Double duy nhất.

Ví dụ:

package com.maixuanviet.predicate;
 
import java.util.Arrays;
import java.util.function.DoublePredicate;
import java.util.function.IntPredicate;
import java.util.function.LongPredicate;
 
public class PredicateExample4 {
 
    public static void main(String[] args) {
 
        System.out.print("IntPredicate: ");
        int[] intNumbers = { 3, 5, 6, 2, 1 };
        IntPredicate intPredicate = i -> i > 5;
        Arrays.stream(intNumbers).filter(intPredicate).forEach(System.out::println);
 
        System.out.print("\nLongPredicate: ");
        long[] longNumbers = { 3, 5, 6, 2, 1 };
        LongPredicate longPredicate = l -> l > 5;
        Arrays.stream(longNumbers).filter(longPredicate).forEach(System.out::println);
 
        System.out.print("\nDoublePredicate: ");
        double[] dbNumbers = { 3.2, 5.0, 6.3, 2.5, 1.0 };
        DoublePredicate dbPredicate = d -> d > 5;
        Arrays.stream(dbNumbers).filter(dbPredicate).forEach(System.out::println);
    }
}

Output của chương trình trên:

IntPredicate: 6
 
LongPredicate: 6
 
DoublePredicate: 6.3

2.6. Sử dụng Predicate 2 đối số với BiPredicate

Như đã nói ở phần trên Predicate chỉ chấp nhận 1 đối số đầu vào và trả về 1 giá trị true/false, để có thể sử dụng Predicate với 2 đối số đầu vào chúng ta sử dụng Interface BiPredicate:

Về cơ bản, interface BiPredicate không khác biệt so với Predicate, ngoại trừ nó chấp nhận 2 đối số đầu vào.

package com.maixuanviet.predicate;
 
import java.util.function.BiPredicate;
 
public class BiPredicateExample {
 
    public static void main(String[] args) {
 
        BiPredicate<Integer, String> condition = (i, s) -> i > 2 && s.startsWith("J");
        System.out.println(condition.test(5, "Java")); // true
        System.out.println(condition.test(2, "Javascript")); // false
        System.out.println(condition.test(1, "C#")); // false
    }
}