What is the difference between a lambda and a method reference at a runtime level?

后端 未结 2 958
花落未央
花落未央 2020-11-29 00:01

I\'ve experienced a problem that was happening using a method reference but not with lambdas. That code was the following:

(Comparator &         


        
2条回答
  •  伪装坚强ぢ
    2020-11-29 00:30

    I want to add the fact that there is actually a semantic difference between a lambda and a method reference to an instance method (even when they have the same content as in your case, and disregarding serialisation):

    SOME_COMPARATOR::compare

    This form evaluates to a lambda object which is closed over the value of SOME_COMPARATOR at evaluation time (that is, it contains reference to that object). It will check if SOME_COMPARATOR is null at evaluation time and throw a null pointer exception already then. It will not pick up changes to the field that are made after its creation.

    (a,b) -> SOME_COMPARATOR.compare(a,b)

    This form evaluates to a lambda object which will access the value of the SOME_COMPARATOR field when called. It is closed over this, since SOME_COMPARATOR is an instance field. When called it will access the current value of SOME_COMPARATOR and use that, potentially throwing an null pointer exception at that time.

    Demonstration

    This behaviour can be seen from the following small example. By stopping the code in a debugger and inspecting the fields of the lambdas one can verify what they are closed over.

    Object o = "First";
    
    void run() {
        Supplier ref = o::toString; 
        Supplier lambda = () -> o.toString();
        o = "Second";
        System.out.println("Ref: " + ref.get()); // Prints "First"
        System.out.println("Lambda: " + lambda.get()); // Prints "Second"
    }
    

    Java Language Specification

    The JLS describes this behaviour of method references in 15.13.3:

    The target reference is the value of ExpressionName or Primary, as determined when the method reference expression was evaluated.

    And:

    First, if the method reference expression begins with an ExpressionName or a Primary, this subexpression is evaluated. If the subexpression evaluates to null, a NullPointerException is raised

    In Tobys code

    This can be seen in Tobys listing of the code of reference, where getClass is called on the value of SOME_COMPARATOR which will trigger an exception if it is null:

    4: invokevirtual #3   // Method Object.getClass:()LClass;
    

    (Or so I think, I'm really not an expert on byte code.)

    Method references in code that is complied with Eclipse 4.4.1 does not throw an exception in that situation however. Eclipse seems to have a bug here.

提交回复
热议问题