I have seen that in Java 8, one can define a comparator like this:
Comparator c = (Computer c1, Computer c2) -> c1.getAge().compareTo(c2.getAge());
which is equivalent to:
Comparator d = new Comparator<Computer> () {
@Override
public int compare(Computer c1, Computer c2){
return c1.getAge().compareTo(c2.getAge());
}
};
I'd like to understand how this works. In the second example, it is fairly simple: A Comparator
object is created with a method compare
which performs the comparison by using the compareTo
method in the age
property of Computer
. This method is simply called by us when we do:
Computer comp1 = new Computer(10);
Computer comp2 = new Computer(11);
d.compare(comp1, comp2); // -1
But what's going on in the first example, when using a lambda? It looks to me like we are setting the Comparator
to be equal to a method that performs comparison. But this cannot be, because a Comparator
object is an object that has a method compare
. I've learned that lambdas can be used with functional interfaces (interfaces with only one method). But Comparator
is not a functional interface (it has many other methods other than compare
!). So how does the Java interpreter know that it is the compare
method we are implementing?
Comparator
is a functional interface (only demands one method). Thus, you can create instances of it by using a lambda expression.
It behaves very similar to other methods of creating instances, such as a regular class which extends or an anonymous class.
The lambda refers to the one method a functional interface demands. Since there is only one method, it is not ambiguous. The lambda names the input arguments and then gives an implementation for the method (it provides a body).
You have the following options to create instances of interfaces or abstract classes:
Supposed we have an interface which only offers one method (it's called functional interface then), we additionally have the following two options to create instances of it:
As example, we want to create a multiplication instance, using the following interface:
@FunctionalInterface
public interface Operation {
int op(int a, int b);
}
Create a class that extends and use new:
public class Multiplicator implements Operation {
@Override
public int op(int a, int b) {
return a * b;
}
}
// Usage
Operation operation = new Multiplicator();
System.out.println(operation.op(5, 2)); // 10
Use an anonymous class:
Operation operation = new Operation() {
@Override
public int op(int a, int b) {
return a * b;
}
};
// Usage
System.out.println(operation.op(5, 2)); // 10
Use a lambda expression:
Operation operation = (a, b) -> a * b;
System.out.println(operation.op(5, 2)); // 10
Use a method reference:
// Somewhere else in our project, in the `MathUtil` class
public static int multiply(int a, int b) {
return a * b;
}
// Usage
Operation operation = MathUtil::multiply;
System.out.println(operation.op(5, 2)); // 10
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