Why can a lambda expression be used as a Comparator?

后端 未结 9 1933
渐次进展
渐次进展 2020-12-16 02:55

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:

<         


        
相关标签:
9条回答
  • 2020-12-16 03:09

    The interface Comparator is a Functional Interface, this means this interface can only contains one abstract method.

    Then you can use lambda expression to define the implementation of this abstract method, basically (d1,d2) -> d1.getWeight() - d2.getWeight(); is the implementation of the abstract method int compare(T o1, T o2);.

    As a functionnal Interface contains only one abstract method, you can use lambda expression to define the implementation of such interface

    0 讨论(0)
  • 2020-12-16 03:11

    You can think of a lambda as a method that doesn't belong to a class, that can be passed around like a piece of data.

    Or, with a very small mental shift, you can think of it as an object with only one method.

    There is a set of interfaces marked as functional interfaces. This is mentioned in the Javadoc as:

    Functional Interface:

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

    That's a technical way of saying that because they have only one method, and they're marked as functional, the compiler can treat a lambda as an object with that interface. It knows to use the lambda as the implementation of the one method in the interface.

    So you can do:

    Comparator<Pet> byNameComparator = (f1,f2) -> f1.name().compareTo(f2.name());
    Predicate<Customer> isVip = cust -> cust.orderCount > 20;
    Callable<Item> getResult = () -> queue.getItem();
    Function<Integer,Integer> multiply = (a,b) -> a * b;
    

    ... and so on.

    And wherever a parameter's type is a functional interface, you can instead use a lambda directly, so given:

     public void sort(Comparator cmp);
    

    ... you can call it as:

     foo.sort( (a,b) -> a.name().compareTo(b.name()));
    
    0 讨论(0)
  • 2020-12-16 03:17

    Basically lambdas behave very much like inner classes but allow for a nicer syntax to be used with less overhead.

    With Java8 Comparator is a @FunctionalInterface (JavaDoc) which makes it usable with lambda expressions. That is you can define a Bi-Function (function with two arguments) with return type int and use it as Comparator, which is done in your second example. Both Comparator instances can be used in exactly the same way in your remaining code.

    0 讨论(0)
  • 2020-12-16 03:19

    In the first code block the created object instance implements Comparator<Duck>, but the corresponding class has no name (is anonymous).

    In the second code block, the same thing happens. Because the Comparator interface only defines a single method (named compare), it is possible to abbreviate the creation of an (anonymous) implementation of the interface using a lambda expression.

    The variable byWeight can be used the same way in both examples. Everywhere a Comparator<Duck> is required, byWeight can be used - which corresponds to the type information of the variable. Internally, whenever compare is invoked on this implementation, the definition provided using the lambda expression is used.

    0 讨论(0)
  • 2020-12-16 03:21

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-16 03:25

    In the first way you're creating a new anonymous class (that has a method with a behaviour).

    In the second way you're just exposing the behaviour (consider this like a way to share a function, a method, without see the surrounding class even if it is created transparently).

    I remember was explained clearly in the Java Tutorial - The Lambda Expressions

    One issue with anonymous classes is that if the implementation of your anonymous class is very simple, such as an interface that contains only one method, then the syntax of anonymous classes may seem unwieldy and unclear. In these cases, you're usually trying to pass functionality as an argument to another method, such as what action should be taken when someone clicks a button. Lambda expressions enable you to do this, to treat functionality as method argument, or code as data.

    I suggest to focus your mind that, using lambdas, you're trying just to expose a behaviour to some class or component, your example may be to the Collections.sort .

    The lambdas give you the opportunity to have a more clear and simple expression avoiding the boilerplate of the anonymous class declarations.

    0 讨论(0)
提交回复
热议问题