谓词的含义和用法 Java 8

Meaning and usage of Predicates Java 8

我正在学习函数式接口、lambda 表达式和谓词的概念。我可以使用互联网上的示例编写程序,但我仍然不清楚某些结构。

这是我的 class Employee,有 3 个数据成员、一个构造函数和相应的 setter 和 getter。

package lambdaandrelated;

public class Employee {

    private String name;

    private String gender;

    private int age;

    public Employee(String name, String gender, int age) {
        super();
        this.name = name;
        this.gender = gender;
        this.age = age;
    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

这是另一个 class 有 3 种检查方法:

一个。雇员是否为男性。 b.雇员是否为女性。 C。雇员的年龄是否大于过去的年龄。

package lambdaandrelated;

import java.util.function.Predicate;

    public class EmployeePredicates {

        public static Predicate<Employee> isMale(){
            return emp -> emp.getGender().equalsIgnoreCase("Male");  - **Line 1**
        }

        public static Predicate<Employee> isFemale(){
            return emp -> emp.getGender().equalsIgnoreCase("Female");
        }

        public Predicate<Employee> isGreaterThan(Integer age){
            return emp -> emp.getAge()>age;
        }
    }

这是我的主class:

package lambdaandrelated;

import java.util.function.Predicate;

public class EmployeeMain {

    public static void main(String[] args) {
        Employee emp1 = new Employee("Parul", "Female", 24);
        Employee emp2 = new Employee("Kanika", "Female", 24);
        Employee emp3 = new Employee("Sumit", "Male", 27);


        Predicate<Employee> predicate1 = new EmployeePredicates().isGreaterThan(23);
        System.out.println(predicate1);  **Line2**
        boolean value = predicate1.test(emp3);
        System.out.println(value);

        boolean value1 = predicate1.negate().test(emp3);  **Line3**
        System.out.println(value1);

        System.out.println(predicate1.negate()); **Line4**



    }
}

我的疑问:

1)第1行是Predicate接口的test()方法的实现吗?如果是,为什么 return 类型的方法 isMale()Predicate<Employee> 而不是 boolean

2) 第 2 行的 o/p 即变量 'predicate1' 的值为“ lambdaandrelated.EmployeePredicates$$Lambda$1/746292446@4617c264 ”。但是变量'predicate1'的类型是Predicate<Employee>。这里的后台发生了什么?

3) Predicate 的否定是什么意思?如果它意味着否定 boolean o/p,那么它不应该应用于 test() 方法的 o/p 而不是应用于谓词本身(如第 3 行中所做的那样) .如果它意味着否定 Predicate 对象,那么 test() 方法的 o/p 为什么以及如何被否定?将 boolean 值从 true 更改为 false 的后台发生了什么。是谓词对象的类型 returned 决定了 test() 方法的 o/p 吗?

4) 当 negate() 的 return 类型也是 Predicate<T> 时,Line4 的 o/p 也是 "java.util.function.Predicate$$Lambda/2055281021@5ca881b5",这看起来不错。那为什么isMale()/isFemale()的o/p格式不一样呢?

  1. isMale() 是一种 return 是 Predicate<Employee> 的方法,它是一个功能接口,具有接受 Employee 和 return一个boolean.

    该方法不会 return 给定 Employee 的布尔值。它 return 是一个可以应用于任何 Employee 和 return 布尔值的函数。

  2. 当你打印一个引用变量时,你看到的是该变量引用的对象的运行时类型,而不是它的编译时类型(当然,这是假设运行时类型没有覆盖toString)。 lambda 表达式是一种实现功能接口的方法。如果您使用某些 class Predicate<Employee> predicate1 = new ClassThatImplementsPrdicateEmployee() 显式实现接口,打印 predicate1 将为您提供 class ClassThatImplementsPrdicateEmployee 而不是 Predicate 的名称。同样,对于 lambda 表达式,编译器生成 returned 名称,类似于匿名 class 实例的情况。

  3. 至于negate的作用,看默认实现:

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    

    它return是一个Predicate,其实现是对给定参数应用原始Predicatetest()方法的否定。

1) 每当您使用 lambda 时,您都在创建一个 函数 。在这种情况下,您指定该函数应该是 Predicate 类型。由于Interface Predicate只有一个方法要实现,'->'后面的部分是该函数的实现。

2) println 将调用该对象上的 toString(),该对象是 Predicate 对象。 Lamdas 将有一个 toString 方法的默认实现,某种 可以帮助您找到它的创建位置。

3) .negate() 将创建一个 全新的 谓词,它又可以被测试。它将return相反的值。

对于 1:

你可以写得略有不同,可能是有道理的:

public static Predicate<Employee> isMale() {
    return new Predicate<Employee>() {
        @Override
        public boolean test(Employee emp) {
            return emp.getGender().equalsIgnoreCase("Male");
        }
    };
}

boolean 必须是 Predicate#test 的 return 类型。这个结构:

 return emp -> emp.getGender().equalsIgnoreCase("Male");

实际上 return 一个 Predicate 有一个 return 布尔值的测试方法。

为 2

当编译器看到一个 lambda 函数时,它将 去糖 到 class 中您实际编写此 Predicate 的实例方法。

所以在你的 EmployeePredicates 中你会有一些这样的方法(你可以通过 javap 反编译并查看它们):

private static boolean lambda$isFemale[=12=](Employee employee ){
    // your isFemale logic here
}

然后class在运行时为你生成一个Predicate调用这个方法。 class 的名字是:EmployeePredicates$$Lambda。您可以通过 运行 您的代码再次看到此 class 名称和代码:

-Djdk.internal.lambda.dumpProxyClasses = /Your/Path

所以这就是 class 的来源,名称是由编译器生成的。

为 3

基本上是指 != 对于 Predicate 而不是 ==。如果你看一下 negate 的实现,这应该很清楚:

default Predicate<T> negate() {
    return (t) -> !test(t);
}

应用测试,然后否定结果。