我对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 + "";
答案 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
的值实际使用之前对其进行缓存。
答案 2 :(得分:3)
还有一件事,为什么我在这里不需要return语句?
仅指定一个lambda语句时,其值会自动从lambda返回。
Function<Integer, String> f = s::substring;
Java与pass-by-value.一起使用,因此f
是参考副本。