Search code examples
javajava-8method-referencefunctional-interface

Please Explain Java 8 Method Reference to instance Method using class name


public interface MyFunc<T> {

    boolean func(T v1, T v2);

}
public class HighTemp {

    private int hTemp;

    HighTemp(){

    }
    public HighTemp(int ht) {
        this.hTemp = ht;
    }

    boolean sameTemp(HighTemp ht2){
         return hTemp == ht2.hTemp;
    }

     boolean lessThanTemp(HighTemp ht2){
        return hTemp < ht2.hTemp;
    }
}
class InstMethWithObjRef {

    static <T> int counter(T[] vals, MyFunc<T> f, T v){
        int count = 0;

        for (int i = 0; i < vals.length; i++) {
            if(f.func(vals[i], v)) count++;
        }
        return count;
    }
    public static void main(String[] args) {
        int count;
        //Create an array of HighTemp objects.
        HighTemp[] weekDayHighs = {new HighTemp(89), new HighTemp(82),
                                   new HighTemp(90), new HighTemp(89),
                                   new HighTemp(89), new HighTemp(91),
                                   new HighTemp(84), new HighTemp(83)};
        count = counter(weekDayHighs, HighTemp::lessThanTemp,new HighTemp(89));     
        System.out.println(count);          
    }
}

Please explain how

  1. boolean sameTemp() is compatible with func() in Functional interface.
  2. sameTemp() method got implemented on func() in Functional Interface.
  3. count = counter(weekDayHighs, HighTemp::sameTemp, new HighTemp(89)); is working

Please Explain All points separately.


Solution

  • Equivalent lambda expression of HighTemp::lessThanTemp is

    (highTemp1, highTemp2) -> {
         return highTemp1.lessThanTemp(highTemp2);
    } 
    

    This is one of the features of Java8 named Reference to an Instance Method of an Arbitrary Object of a Particular Type


    Consider following example,

    interface FIface<T> {
        int testMethod(T a, T b);
    }
    
    class Test2 {
    
        private String str;
    
        Test2(String str) {
            this.str = str;
        }
    
        int ok(Test2 test2) {
            System.out.println("Currnet String : "+ this.str);//Refer to t1
            System.out.println("Test String : "+test2.str);//Refer to t2
            return 0;
        }
    
    }
    
    public class Test {
    
        public static <T> int checkCall(T t1, T t2, FIface<T> fiFace) {
            //Here Test2 :: ok is equivalent to t1.ok(t2)
            return fiFace.testMethod(t1, t2);
        }
    
        public static void main(String[] args) {
            checkCall(new Test2("a"), new Test2("b"), Test2 :: ok);
        }
    
    }
    

    OUTPUT

    Currnet String : a
    Test String : b
    

    Note here that Test2 :: ok is valid for the call even ok method is not static.

    When you call the method checkCall for the functional interface you still have two arguments which are t1 and t2 and for that valid lambda expression can have parameters as (Test t1, Test t2) so your method Test2 :: ok here becomes valid for the call. Internally it works this way t1.ok(t2).

    So, fiFace.testMethod(t1, t2); will will invoke method as t1.ok(t2)