Java中String方法的函数指针

时间:2018-07-31 21:22:21

标签: java lambda

我对lambda不太了解。

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

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

还有一件事,为什么我在这里不需要return语句?

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

3 个答案:

答案 0 :(得分:17)

JLS, Section 15.13.3描述了方法引用的运行时评估。

  

方法引用表达式求值的时间比lambda表达式(第15.27.4节)更复杂。当方法引用表达式的::分隔符之前具有表达式(而不是类型)时,将立即对该子表达式求值。存储评估的结果,直到调用相应功能接口类型的方法为止;此时,结果将用作调用的目标参考。这意味着::分隔符之前的表达式仅在程序遇到方法引用表达式时才被评估,并且不会在随后对功能接口类型的调用上重新评估。

(加粗强调)

基本上,对方法方法参考的s的参考都将存储起来,以供以后执行。在这里,字符串"Hello World"被保存以供以后执行方法引用。因此,即使在方法引用的声明之后将s设置为null,但在执行Function之前,它仍将使用字符串"Hello World"

将某些内容设置为null并不能保证垃圾收集器将对其进行收集,也不能保证立即对其进行收集。

此外,这里的方法引用中仍然有一个引用,因此这里根本不会收集垃圾。

最后,lambda表达式主体具有2种形式:一个表达式和一个语句块(可能带有return语句)。与

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

那是一个表达。等效的block语句为:

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

答案 1 :(得分: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));

以上内容未编译,因为s在lambda之外被更改,因此它实际上不是最终的。因此,我们可以推断出使用方法引用可以在s的值实际使用之前对其进行缓存。

请参阅:Is method reference caching a good idea in Java 8?

答案 2 :(得分:3)

  

还有一件事,为什么我在这里不需要return语句?

仅指定一个lambda语句时,其值会自动从lambda返回。

Function<Integer, String> f = s::substring;

Java与pass-by-value.一起使用,因此f是参考副本。