shodz shodz - 2 months ago 10
Java Question

Java Lambda Expression

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?

Answer

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.

Comments