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?
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:
from here (section 4)
List of parameters of your
compare()
(String
,String
) can be matched to list of parameters ofString#compareTo()
(this
,String
) and their return types are also the same (int
), so one can be used as lambda when another is expected.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:
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 writtenComparable::compareTo
. Since the referenced method has no type parameters on its own, your type argument has no effect. E.g. you could writeComparable::<Button>compareTo
with the same result.The referenced method has the functional signature
(Comparable,Comparable) → int
as it consumes twoComparable
s when invokingComparable.compareTo
on oneComparable
, passing the secondComparable
as argument (and it will return anint
). This matches the functional signature of yourinterface
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 concreteComparable
implementation using this function.