有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么lambdas中使用的局部变量必须是final或有效final?

这个问题在这里已经有了答案:

但是我读了一篇帖子。它举了一个例子:

Supplier<Integer> incrementer(int start) {
  return () -> start++;
}

代码将抛出编译错误。这篇文章试图解释原因并说:

The basic reason this won't compile is that the lambda is capturing the value of start, meaning making a copy of it. Forcing the variable to be final avoids giving the impression that incrementing start inside the lambda could actually modify the start method parameter. But, why does it make a copy? Well, notice that we are returning the lambda from our method. Thus, the lambda won't get run until after the start method parameter gets garbage collected. Java has to make a copy of start in order for this lambda to live outside of this method.

我无法理解它的解释,我有两个问题:

  1. “在start方法参数被垃圾回收之前lambda不会运行”是什么意思
  2. 为什么要复制

共 (2) 个答案

  1. # 1 楼答案

    当您从函数返回时,函数中声明的未“返回”的变量和对象将变为“超出范围”,程序员不应再访问这些变量和对象。对于java,垃圾收集器最终会删除这些对象

    public String enterNewScope(String a, String b) {
        String c = a + b;
        String d = b + c;
        String e = c + d;
    
        return d;
    }
    
    public static void main(String...args) {
        //The variables a, b, c, and e are now out of scope
        //d is returned by the function so it's still in use.
        String dReturned = enterNewScope("hello", "world");
    }
    

    函数Supplier<Integer> incrementer(int start) {...}返回一个lambda,但您只能在函数已经返回后使用lambda,这意味着只要您能够使用该lambda,变量“start”就超出了范围。因此,Java将复制“start”变量,以防在调用lambda时无法访问它

    查看另一个答案以了解更多详细信息:Lambda Expression and Variable Capture

  2. # 2 楼答案

    1. 这意味着在调用^{}对象的get()方法之前,不会执行lambda代码(start++部分),这发生在incrementer()方法调用方的某个地方,即incrementer()方法返回后的某个时间

      不管是谁写的,都是大错特错,因为参数在堆栈上,而不是堆上,所以它们不会被“垃圾收集”。考虑到这样一个巨大的错误,我建议你忽略那篇帖子,因为作者不知道他在说什么

    2. 您提供的第一个链接的accepted answer中已经介绍了这一点。我建议你读一读