Search code examples
javalambdajava-stream

How does java's double colon operator refer non-static method using class name


I have written a code like this:

public class MyClass implements Comparable{

    int value;

    MyClass(int value){
        this.value = value;
    }
    public static void main(String[] args) {

        MyClass obj1 = new MyClass(30);
        MyClass obj2 = new MyClass(5);
        MyClass obj3 = new MyClass(15);
        List<MyClass> classList = new ArrayList<>();
        classList.add(obj1);
        classList.add(obj2);
        classList.add(obj3);

        List<MyClass> list2 =classList.stream().sorted(MyClass::compareTo).collect(Collectors.toList());
        list2.stream().forEach(x-> System.out.println(x.value));

    }

    @Override
    public int compareTo(Object o) {
        MyClass obj = (MyClass)o;
        if(this.value<obj.value){
            return +1;
        }else return -1;
    }
}

This code compiles successfully gives me the correct output as expected-

30
15
5

I have 2 questions

  1. How are we able to refer non-static method compareTo using Myclass(classname)? Shouldn't we be expected to use object of my class to refer compareTo()?

  2. How are we able to use compareTo() method which takes only 1 parameter, whereas sorted() expects Comparator Interface whose abstract class compare() takes 2 parameters?


Solution

  • The Stream method sorted takes a Comparator<T> as parameter. This is a functional interface, so you can use a lambda expression or method reference as parameter that adheres to this interface. The method signature is as follows:

    int compare(T var1, T var2);
    

    So, for example, the following lambda expression is valid:

    (MyClass a, MyClass b) -> a.compareTo(b)
    

    A method reference can refer to static methods, but in this specific context, the type of the method reference can also replace the first parameter, so the following expression is equivalent to the above:

    MyClass::compareTo
    

    Similarly, you can do the following:

    (String a, String b) -> a.equals(b)
    String::equals
    

    Or things like this:

    (String a) -> "b".equals(a)
    "b"::equals