Java Lambda Expression

南楼画角 提交于 2019-12-10 00:35:20

问题


I am currently learning lambda expressions on JDK 1.8. I have come across some code I have found that I do not understand.

Here is the code:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.lang.Comparable;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args ) throws Exception
    {

        List<String> list = Arrays.asList("a", "b", "c");
        sort(list, Comparable::<String>compareTo);

    }

    interface MyComparable {
        public <T extends Comparable<T>> int compare(T obj1, T obj2 );
    }

    public static <T extends Comparable<T>> void sort(List<T> list, MyComparable comp) {

        int n = comp.compare("5","2");
        System.out.println(n);
    }

}

comp.compare("5", "3") eventually executes "5".compareTo("2"). My understanding was the compiler needs to find a static method with same signature as

public <T extends Comparable<T>> int compare(T obj1, T obj2 );

I have created such a method and it works. I do not understand why the java compiler calls "5".compareTo("2"). Their method signitures are not the same.

Any information as to why the compiler generates this kind of code?


回答1:


If you are trying to learn method references, you should resort to some sort of learning material, e.g. Oracle’s Java tutorial. There you find:

Kinds of method references

       Kind                                                                           Example

  • Reference to a static method ContainingClass::staticMethodName
  • Reference to an instance method of a particular object containingObject::instanceMethodName
  • Reference to an instance method of an arbitrary object of a particular type ContainingType::methodName
  • Reference to a constructor ClassName::new

So you see, method references are not restricted to static methods.

Your method reference Comparable::<String>compareTo matches the kind “Reference to an instance method of an arbitrary object of a particular type”.

At this point it’s worth noting that you are actually referencing the method Comparable.compareTo as if you had written Comparable::compareTo. Since the referenced method has no type parameters on its own, your type argument has no effect. E.g. you could write Comparable::<Button>compareTo with the same result.

The referenced method has the functional signature (Comparable,Comparable) → int as it consumes two Comparables when invoking Comparable.compareTo on one Comparable, passing the second Comparable as argument (and it will return an int). This matches the functional signature of your interface

interface MyComparable {
    public <T extends Comparable<T>> int compare(T obj1, T obj2 );
}

so the method reference can be used in this context.

I have simplified the functional signatures; actually they are (T,T)→int using <T extends Comparable<T>>, therefore you can only compare two instances of the same concrete Comparable implementation using this function.




回答2:


So you're wondering how a method reference with different signature than expected, can be sent as lambda expression. But they don't need to be fully the same. Basically, only list of parameters and return type matters:

A lambda expression can be assigned to a target type T if all of the following conditions hold:

  • T is a functional interface type

  • The lambda expression has the same number of parameters as T's method, and those parameters' types are the same

  • Each expression returned by the lambda body is compatible with T's method's return type

  • Each exception thrown by the lambda body is allowed by T's method's throws clause

from here (section 4)

List of parameters of your compare() (String, String) can be matched to list of parameters of String#compareTo() (this, String) and their return types are also the same (int), so one can be used as lambda when another is expected.



来源:https://stackoverflow.com/questions/29802633/java-lambda-expression

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!