Reputation: 45
I am trying to learn lambda expressions. I am currently referring to OCP study guide.
In one example of lambda expression there is a Animal class and another another interface called CheckTrait. The functioning of lambda expression is very confusing for me. Example code is as shown below:
Without lambda expression.
public interface CheckTrait {
public boolean test(Animal a);
}
public class Animal implements CheckTrait{
private String species;
private boolean canHop;
private boolean canSwim;
public Animal(String species, boolean canHop, boolean canSwim) {
super();
this.species = species;
this.canHop = canHop;
this.canSwim = canSwim;
}
public boolean canHop() {
return this.canHop;
}
public String toString() {
return species;
}
public boolean canSwim() {
return this.canSwim;
}
@Override
public boolean test(Animal a) {
return a.canHop();
}
}
public class FindMathcingAnimals {
private static void print(Animal animal, CheckTrait trait) {
if(trait.test(animal)){
System.out.println(animal+" can hop" );
}else {
System.out.println(animal+" cannot hop");
}
}
public static void main(String[] args) {
Animal animal2= new Animal("Kangaroo", true, false);
print(animal2,animal2);
}
}
When we run the above class we get the output as Kangaroo can hop
With lambda expression
public interface CheckTrait {
public boolean test(Animal a);
}
public class Animal {
private String species;
private boolean canHop;
private boolean canSwim;
public Animal(String species, boolean canHop, boolean canSwim) {
super();
this.species = species;
this.canHop = canHop;
this.canSwim = canSwim;
}
public boolean canHop() {
return this.canHop;
}
public String toString() {
return species;
}
public boolean canSwim() {
return this.canSwim;
}
}
public class FindMathcingAnimals {
private static void print(Animal animal, CheckTrait trait) {
if(trait.test(animal)){
System.out.println(animal+" can hop" );
}else {
System.out.println(animal+" cannot hop");
}
}
public static void main(String[] args) {
Animal animal2= new Animal("Kangaroo", true, false);
print(animal2,s->s.canHop());
}
}
My Question is, In the below line print(animal2,s->s.canHop());
I am not passing any value to s but just an expression, then how is the program computing the result? I am aware that it is taking the animal object and checking the canhop variable just by intuition,but I am not understanding the logic here. Kindly provide your thoughts.
Edit: based on Aominè's answer:
So, can i conclude that. In the print method I am passing the behavior for CheckTrait, and in the print method can be reduced as:
step1: if(trait.test(animal)){
step2: if(s.canHop())
step3: if(animal.canHop)
the above steps are just for my understanding.
Upvotes: 2
Views: 669
Reputation: 56393
I am not passing any value to s but just an expression, then how is the program computing the result?
below you pass in a behaviour (a function) as the second argument to the print method which will be used within the print method.
print(animal2, s -> s.canHop());
this function reads as "given an element say s
, call the canHop()
method on the element"
now within the print method when you do:
if(trait.test(animal)){ ... }
you're calling trait.test(animal)
and passing the animal object to the function we passed in, we then apply the function to the input animal.
if it helps this:
print(animal2,s -> s.canHop());
can be seen as being the same as:
print(animal2, new CheckTrait() {
@Override
public boolean test(Animal s) {
return s.canHop();
}
});
edit:
as you've mentioned the method calls can be seen as:
if(trait.test(animal)){..} -> if(s.canHop()){..} -> if(animal.canHop){..} // pseudocode
Upvotes: 3
Reputation: 12463
I assume you are not familiar with functional programming so you can look at it this way - a lambda is like an abbreviation. Basically, CheckTrait
is a class that contains a method that takes an Animal
and returns a boolean indicating whether it has a cerain property. It doesn't perform any external operations or change any values or anything, it just computes one value (boolean) from an other (Animal). This is a function, in the purest sense.
In older versions of Java, to create an object that represents a CheckTrait
function, you would have to do this
CheckTrait canHop = new CheckTrait() {
public boolean test(Animal a) {
return a.canHop();
}
}
Animal a = ...;
canHop.test(a);
This is a lot to type, especially since the only important details here are the input argument (Animal a
), and the output function (return a.canHop()
). So Java borrowed a syntax from functional programming languages where you can specify just these two elements, leaving out all he noise, and it automatically translates to the code above.
CheckTrait canHop = (Animal a) -> { return a.canHop(); }
Animal a = ...;
canHop.test(a);
This only works for interfaces with a single method though. Even better they made it so if the compiler can guess the input type, and the function consists only of a return statement, you can omit the type and even the return
keyword.
CheckTrait canHop = a -> a.canHop();
Animal a = ...;
canHop.test(a);
And that's how lambda's work. They are basically shortened forms of anonymous classes.
TLDR; print(animal2,s->s.canHop())
is short for
print(animal2, new CheckTrait() {
public boolean test(Animal a) {
return a.canHop();
}
});
Upvotes: 1
Reputation: 7553
A lambda expression is just a function.
The form
s -> s.canHop()
specifies a function that receives a single parameter, and invokes the canHop
function on that parameter.
Since print
is expecting a CheckTrait
, the compiler knows that the type of the parameter is Animal
.
Upvotes: 0