I was learning the concepts of functional interfaces, lambda expression and predicates. I could write a program using examples on the internet but I am still not clear with certain constructs.
This is my class Employee
with 3 data members, a constructor and corresponding setters & getters.
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;
}
}
This is another class that has got 3 methods to check:
a. whether the employee is a male. b. whether the employee is a female. c. whether the age of the employee is greater than the age passed.
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;
}
}
This is my main 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**
}
}
My doubts :
1) Is Line 1 the implementation of test()
method of Predicate
interface? If yes, why is the return type of method isMale()
a Predicate<Employee>
and not a boolean
?
2) The o/p of Line 2 i.e the value of variable 'predicate1' is " lambdaandrelated.EmployeePredicates$$Lambda$1/746292446@4617c264 ". But the variable 'predicate1' is of type Predicate<Employee>
. What is happening in the background here?
3) What do we mean by negation of a Predicate
? If it means negating the boolean
o/p, then should it not be applied on the o/p of test()
method rather than applying it on the predicate itself (as done in Line3). If it means negating the Predicate
object, then why and how is the o/p of test()
method getting negated? What happens in the background that is changing the boolean
value from true
to false
. Is it the type of predicate object returned that decides the o/p of test() method?
4) Also the o/p of Line4 is "java.util.function.Predicate$$Lambda$2/2055281021@5ca881b5" when the return type of negate()
is also Predicate<T>
which seems fine. Then why the o/p of isMale()
/isFemale()
not of the same format?
isMale()
is a method that returns a Predicate<Employee>
, which is a functional interface having a single method that accepts an Employee
and returns a boolean
.
The method doesn't return that boolean for a given Employee
. It returns a function that can be applied on any Employee
and return a boolean.
When you print a reference variable, you see the runtime type of the object referenced by that variable, not its compile time type (this is, of course, assuming the runtime type doesn't override toString
). A lambda expression is a way to implement a functional interface. If you implemented the interface explicitly with some class Predicate<Employee> predicate1 = new ClassThatImplementsPrdicateEmployee()
, printing predicate1
would give you that name of that class ClassThatImplementsPrdicateEmployee
and not Predicate
. Similarly, in the case of a lambda expression, the compiler generates the returned name, similar to what happens with anonymous class instances.
As for what negate does, look at the default implementation :
default Predicate<T> negate() {
return (t) -> !test(t);
}
It returns a Predicate
whose implementation is the negation of applying the original Predicate
's test()
method on the given argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With