【问题标题】:Are Lambda Captured Variables Guarenteed To Survive Entire life of Lambda? [duplicate]Lambda 捕获变量是否保证在 Lambda 的整个生命周期中都存在? [复制]
【发布时间】:2021-11-13 12:18:26
【问题描述】:

在 Java 中,捕获的 lambda 变量的值可以在原始变量范围之外使用,如下所示:

interface MyInterface{
    void doSomething(  );
}

class Example {
 MyInterface lambda;
 public static void main(String[] args) {
     Example e = new Example();
     e.f1();
     e.f2();
 }
 void f1() {
     int local = 777;
     lambda = () -> System.out.println(local);
 }
 void f2() {
     lambda.doSomething(); // prints 777
 }
}

匿名类也可以做到这一点。我怀疑实现会通过复制捕获本地值来做到这一点。

规范是否保证捕获的本地人能够在 lambda 中存活多久?

我希望参考文档中的相关段落。 (我找了,没找到)

【问题讨论】:

  • 我现在明白了。你看过编译后的代码吗?这可能会告诉你一些事情。
  • @HovercraftFullOfEels 好的。由于我对字节码的糟糕命令,它看起来确实像是 777 的副本被加载到 f1 中返回对象的堆栈中。但这可能只是一个实现细节。我正在寻找更正式的东西。
  • "规范是否保证捕获的本地变量能够在 lambda 表达式中存活多久?" - 是的。我不知道概述它的确切 JLS 段落,但这至少部分是为什么在 lambda 中访问的变量必须是 final 或实际上是 final

标签: java lambda closures


【解决方案1】:

我怀疑实现会通过复制捕获本地值来做到这一点。

正确。因为如果捕获的本地被修改,这会令人难以置信的混乱,javac 将简单地拒绝编译您的代码,除非捕获的变量是 [A] 标记为 final 或 [B] '有效地最终',这是在规范,这意味着:您可以将其标记为 final。

只要需要,此副本就会存在。一般来说,文档向您保证,除非您涉及 JNI,否则您无法在 java 中获取核心转储,并且垃圾收集规范不会比这更进一步。

【讨论】:

    【解决方案2】:

    6.5.6.1,据说(强调我的)

    如果声明声明了一个在简单表达式之前明确分配的最终变量,则名称的含义是该变量的。否则,表达式名的含义就是声明所声明的变量。

    因此,您的 lambda 中的 local 表示 777,即您分配给 local 的(最终)值。这是通过复制您正确怀疑的变量来实现的。局部变量是否“存活”在这里并不重要。

    根据另一部分,局部变量不会“存活”(4.12.3):

    当声明不再在范围内时,局部变量将不复存在。

    当您在f2 中运行 lambda 时,局部变量的声明超出范围,因此它“不再存在”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 1970-01-01
      • 2015-03-13
      • 1970-01-01
      • 2020-05-13
      相关资源
      最近更新 更多