Reputation: 329
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?
Upvotes: 4
Views: 3800
Reputation: 120848
For 1:
You could have written it slightly different, may be that would make sense:
public static Predicate<Employee> isMale() {
return new Predicate<Employee>() {
@Override
public boolean test(Employee emp) {
return emp.getGender().equalsIgnoreCase("Male");
}
};
}
boolean must be the return type of Predicate#test
. And this construct :
return emp -> emp.getGender().equalsIgnoreCase("Male");
actually return a Predicate
that has a test method that returns boolean.
For 2
When the compiler sees a lambda function it will de-sugare that to an instance method inside the class where you actually wrote this Predicate.
So in your EmployeePredicates
you will have some methods like this(you can decompile and sees those via javap
):
private static boolean lambda$isFemale$0(Employee employee ){
// your isFemale logic here
}
Then there will be a class generated at runtime for you Predicate
that will call this method. That classes name is : EmployeePredicates$$Lambda$1
. You can again see this class name and code by running your code with :
-Djdk.internal.lambda.dumpProxyClasses = /Your/Path
So this is where the class comes from and the name is generated by the compiler.
For 3
Basically is means !=
for a Predicate
instead of ==
. If you look at the implementation of negate
this should be clear:
default Predicate<T> negate() {
return (t) -> !test(t);
}
apply test, then negate the result.
Upvotes: 4
Reputation: 393791
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.
Upvotes: 4
Reputation: 695
1) Whenever you use a lambda, you are creating a function. In this case you are specifying that the function should be of type Predicate. Since the Interface Predicate only has one method to implement, the part after the '->' is the implementation of that function.
2) println will call the toString() on that object, which is the Predicate object. Lamdas will have a default implementation of the toString method which kind of helps you find where it was created.
3) .negate() will create a brand new predicate, which in turn can be tested. It will return the opposite value.
Upvotes: 1