I\'ve experienced a problem that was happening using a method reference but not with lambdas. That code was the following:
(Comparator &
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::compareThis 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.
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"
}
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, aNullPointerExceptionis raised
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.