Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function pointer to String method in Java

Tags:

java

lambda

I don't understand a couple of things with lambda.

String s = "Hello World";       
Function<Integer, String> f = s::substring;
s = null;
System.out.println(f.apply(5));

Why is the f.apply method still working if s = null. After all, the String object should be deleted by the GC because there is no pointer that points to the object.

One more thing, why don't I need a return statement here?

Function<Integer, String> f = t -> t + "";
like image 544
user5327287 Avatar asked Jul 31 '18 21:07

user5327287


2 Answers

The JLS, Section 15.13.3 describes the runtime evaluation of method references.

The timing of method reference expression evaluation is more complex than that of lambda expressions (§15.27.4). When a method reference expression has an expression (rather than a type) preceding the :: separator, that subexpression is evaluated immediately. The result of evaluation is stored until the method of the corresponding functional interface type is invoked; at that point, the result is used as the target reference for the invocation. This means the expression preceding the :: separator is evaluated only when the program encounters the method reference expression, and is not re-evaluated on subsequent invocations on the functional interface type.

(bold emphasis mine)

Basically the reference to s as it is for the method reference is stored for later execution. Here, the string "Hello World" is saved for later execution of the method reference. Because of this, even if you set s to null after the declaration of the method reference, but before you execute the Function, it will still use the string "Hello World".

Setting something to null does not guarantee that the garbage collector will collect it, and it won't guarantee that it's collected immediately.

Also, here, there still is a reference in the method reference, so it won't get garbage collected at all here.

Finally, lambda expression bodies have 2 forms: an expression and a block of statements with (possibly) a return statement. With

Function<Integer, String> f = t -> t + "";

That is an expression. The block statement equivalent would be:

Function<Integer, String> f = t -> { return t + "";};
like image 84
rgettman Avatar answered Oct 16 '22 08:10

rgettman


Let's convert that method reference to a lambda and see what happens:

String s = "Hello World";
Function<Integer, String> f = i -> s.substring(i); // Doesn't compile!
s = null;
System.out.println(f.apply(5));

The above doesn't compile because s is being changed outside of the lambda, so it is not effectively final. Therefore, we can deduce that using a method reference caches the value of s before it's actually used.

See: Is method reference caching a good idea in Java 8?

like image 37
Jacob G. Avatar answered Oct 16 '22 07:10

Jacob G.