为什么在lambda表达式中使用的局部变量必须是final或有效final的?

5 浏览
0 Comments

为什么在lambda表达式中使用的局部变量必须是final或有效final的?

这个问题已经有了答案:

但我读到了一篇文章(为什么Lambda中使用的局部变量必须是final或有效final?)。它举了一个例子:

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

这段代码会导致编译错误。这篇文章试图解释原因并说:

这个代码无法编译的基本原因是lambda捕获了start的值,也就是说创建了一个副本。强制变量为final可以避免让人误以为在lambda内部递增start实际上可以修改start方法参数。但是,为什么会创建副本呢?注意我们正在从方法中返回lambda。因此,在start方法参数被垃圾回收之后,lambda才会被执行。为了让这个lambda在方法之外继续存在,Java需要创建start的副本。

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

  1. "在start方法参数被垃圾回收之后,lambda才会被执行"是什么意思?
  2. 为什么要创建副本?
0
0 Comments

局部变量在lambda中使用必须是final或有效final的原因是,当从函数返回时,函数内部声明的变量和对象如果没有被“返回”,就会变为“超出范围”,程序员不能再访问它们。在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) {
    //变量a、b、c和e现在超出范围
    //d由函数返回,仍然在使用中
    String dReturned = enterNewScope("hello", "world");
}

函数Supplier<Integer> incrementer(int start) {...}返回一个lambda,但是只有在函数已经返回后,你才能使用这个lambda,这意味着当你能够使用lambda时,变量 'start'已经超出范围。因此,Java会在调用lambda时复制你的 'start'变量,以防止无法访问它。

更多细节请参阅这个回答:Lambda Expression and Variable Capture

可以更准确地说,变量 'start'已经超出范围。无法确定start变量是否在内存中,可能强调一下,在Java中,lambda闭包的是值,而不是变量。

好的,编辑回答,试图让问题对提问者更清晰明了。

0
0 Comments

在Lambda表达式中使用的局部变量必须是final或有效final的原因是因为Lambda表达式的代码部分实际上是在调用Lambda所在方法的时候执行的,而不是在Lambda表达式被定义的时候执行。因此,局部变量在Lambda表达式中被引用时必须是final或有效final的,以确保它们在Lambda表达式执行时保持不变。

这个问题的解决方法已经在提供的第一个链接的答案中涵盖了。简而言之,可以遵循以下几个解决方法:

- 将局部变量声明为final或有效final,确保它们在Lambda表达式中不会被修改。

- 将局部变量转换为实例变量或类变量,以便在Lambda表达式中使用。

- 将局部变量封装成一个包含get和set方法的对象,以便在Lambda表达式中进行修改。

总之,为了在Lambda表达式中使用局部变量,必须将其声明为final或有效final,或者通过其他方式将其转换为可以在Lambda表达式中使用的形式。这样可以确保在Lambda表达式执行时,局部变量的值不会发生变化。

0