Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a lambda function become the compare() method of Comparator

Tags:

java

lambda

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?

like image 302
Sahand Avatar asked Jan 01 '23 07:01

Sahand


1 Answers

Explanation

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).


Overview

You have the following options to create instances of interfaces or abstract classes:

  1. Create a class that extends and use new
  2. Use an anonymous class

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:

  1. Use a lambda expression
  2. Use a method reference

As example, we want to create a multiplication instance, using the following interface:

@FunctionalInterface
public interface Operation {
    int op(int a, int b);
}
  1. 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
    
  2. 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
    
  3. Use a lambda expression:

    Operation operation = (a, b) -> a * b;
    System.out.println(operation.op(5, 2)); // 10
    
  4. 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
    
like image 178
Zabuzard Avatar answered Jan 13 '23 13:01

Zabuzard