Java中String方法的函数指针

use*_*287 17 java lambda

我不了解lambda的一些事情.

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

为什么该f.apply方法仍然有效s = null.毕竟,StringGC应该删除该对象,因为没有指向该对象的指针.

还有一件事,为什么我不需要这里的退货声明?

Function<Integer, String> f = t -> t + "";
Run Code Online (Sandbox Code Playgroud)

rge*_*man 18

JLS,第15.13.3描述方法引用的运行评估.

方法参考表达式评估的时间比lambda表达式(第15.27.4节)更复杂.当方法引用表达式在:: separator之前具有表达式(而不是类型)时,将立即计算该子表达式.该评价的结果被存储,直到相对应的功能的接口类型的方法被调用; 此时,结果将用作调用的目标引用.这意味着:: separator之前的表达式仅在程序遇到方法引用表达式时计算,并且不会在函数接口类型的后续调用中重新计算.

(大胆强调我的)

基本上,s存储对方法引用的引用以供稍后执行.这里,"Hello World"保存字符串以便稍后执行方法引用.正因为如此,即使你设置snull方法引用的声明后,但你执行之前Function,它仍然会使用字符串"Hello World".

设置的东西null并不能保证垃圾收集器会收集它,也不能保证它会被立即收集.

此外,在这里,方法参考中仍然有一个引用,所以这里根本不会收集垃圾.

最后,lambda表达式主体有两种形式:表达式和带有(可能)返回语句的语句块.同

Function<Integer, String> f = t -> t + "";
Run Code Online (Sandbox Code Playgroud)

这是一个表达.块语句等效于:

Function<Integer, String> f = t -> { return t + "";};
Run Code Online (Sandbox Code Playgroud)


Jac*_* G. 11

让我们将该方法引用转换为lambda,看看会发生什么:

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

上面没有编译,因为s在lambda之外被更改,所以它不是最终的.因此,我们可以推断出使用方法引用会缓存s实际使用之前的值.

请参阅:方法参考是否在Java 8中缓存了一个好主意?


snr*_*snr 5

还有一件事,为什么我在这里不需要返回声明?

当仅指定单个lambda语句时,其值将自动从lambda返回。

Function<Integer, String> f = s::substring;
Run Code Online (Sandbox Code Playgroud)

Java使用按值传递。因此,f是参考副本。