Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can a lambda expression be used as a Comparator?

In the book OCP Study Guide there is this example about a Comparator that can be initialized in two ways. The first is via an anonymous class like this:

Comparator<Duck> byWeight = new Comparator<Duck>(){
    public int compare(Duck d1, Duck d2){
        return d1.getWeight() - d2.getWeight();
    }
};

This I can understand. According to the book this can be replaced with a lambda expression like this:

Comparator<Duck> byWeight = (d1,d2) -> d1.getWeight() - d2.getWeight();

Now this I don't understand. The lambda expression does not return a Comparator object, which it couldn't now that I think of it since Comparator is an interface.

So does the new operator in the first example refer to the anonymous class that is being made which is called Comparator because that anonymous class implements the Comparator interface?

What exactly is happening in example 2 then? Is an object created somehow out of the lambda expression? In this example you use byWeight as a reference variable right?

I really don't understand this, could anyone please explain? Thank you.

like image 325
Maurice Avatar asked May 09 '17 09:05

Maurice


2 Answers

If you read the documentation of the Comparator interface, you can read:

Functional Interface: This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

The Comparator<T> interface is thus implemented like:

@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);

    // ...

}

Now if we look at the documentation of @FunctionalInterface we see:

An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification. Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

So basically if you have an interface with one abstract method, and you annotate the interface as a @FunctionalInterface, then that interface is a target for functions: in that you more or less construct an anonymous class that implements the functional interface and the function you specify is the implementation of the only abstract method.

In other words, the expression:

Comparator<Duck> byWeight = <somelambda>

is equivalent to:

Comparator<Duck> byWeight = new Comparator<Duck>(){
    public int compare(Duck d1, Duck d2){
        return <somelambda>(d1,d2);
    }
}
like image 131
Willem Van Onsem Avatar answered Nov 10 '22 01:11

Willem Van Onsem


Lambda expression is just a short-hand for a functional interface (an interface with just one function), you don't need to write new/function name just write parameter list in ( yourParameterListHere ) and then -> and after this write what to do/return (i.e function body). you can also write it with { } like

Comparator<Duck> byWeight = (d1,d2) -> { d1.getWeight() - d2.getWeight(); }
like image 22
S Jayesh Avatar answered Nov 10 '22 02:11

S Jayesh