Java中始终捕获未使用的引用变量

Java中始终捕获未使用的引用变量,java,java-8,Java,Java 8,我想知道这是否是一个实现细节 在Java中,为匿名类和lambda捕获使用的局部变量。对于匿名类,无论是否需要,此也在非静态上下文中捕获 然而,即使未用于Oracle JDK 8更新181,也会捕获引用的任何局部变量 public static void main(String[] args) { Thread t = Thread.currentThread(); Runnable run = new Runnable() { @Override

我想知道这是否是一个实现细节

在Java中,为匿名类和lambda捕获使用的局部变量。对于匿名类,无论是否需要,
也在非静态上下文中捕获

然而,即使未用于Oracle JDK 8更新181,也会捕获引用的任何局部变量

public static void main(String[] args) {
    Thread t = Thread.currentThread();
    Runnable run = new Runnable() {
        @Override
        public void run() {
            t.yield();
        }
    };
    Runnable run2 = () -> t.yield();
    run.run();
    run2.run();
}
匿名
Runnable
的字节码为

  // access flags 0x1
  public run()V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    GETFIELD UnusedLocalVariable$1.val$t : Ljava/lang/Thread;
    POP
    INVOKESTATIC java/lang/Thread.yield ()V
   L1
    LINENUMBER 9 L1
    RETURN
   L2
    LOCALVARIABLE this LUnusedLocalVariable$1; L0 L2 0
    MAXSTACK = 1
    MAXLOCALS = 1
如您所见,它捕获了它加载的局部变量,但总是在运行时丢弃

lambda也做了同样的事情,也捕获了变量


始终是这样,还是实现细节?

规范对变量的“引用”和“使用”没有区别。在这方面,您通过调用
t.yield()
来使用变量,尽管您调用的是
静态方法。对于这种情况,规范说

:
  • 如果表单是ExpressionName。[TypeArguments]标识符,然后:
    • 如果调用模式是静态的,则没有目标引用。将计算ExpressionName,但随后将丢弃结果
    • 否则,目标引用是由ExpressionName表示的值
因此,行为符合规范

虽然很明显,评估必须发生,但当它有副作用时,我不会得出这样的结论:字节码序列
ALOAD 0
GETFIELD
POP
是严格要求的,以满足评估变量并丢弃结果的正式规则,因为那个代码根本没有作用

但是,无论这些指令是否存在,都会使用变量
t
,因此必须符合正式要求,即它必须是有效的最终指令

此强制行为是否必须导致捕获内部类resp实例中的值。可能令人惊讶的是,为lambda表达式生成的类完全没有指定。Java语言规范对此没有任何说明


换句话说,当您询问值捕获的一个角情况时,即被引用但不需要的变量的值,甚至是一般情况,即众所周知的规则,即内部类始终保留对封闭的
this
的引用,即使不需要,而lambda表达式不需要,没有出现在官方规范的任何地方。

这被标记为Java 8,但它是否特定于Java 8?如中所述,您是否在最近的任何项目上进行了测试,或者您是否有任何理由相信现在的行为有所不同?
t
只是意外地未使用,因为
Thread.yield()
是一种静态方法。如果要调用
t.setName(“someName”)
则需要捕获
t
。也许java编译器不够聪明,无法避免捕获“表面上使用过,但实际上未使用过”的局部变量。@ThomasKläger我可以理解这是一种Oracle java C不做的优化,但这是因为它是不允许的,例如,像
这个
,或者因为它不平凡。@ThomasKläger它可以,但是
x
不是
final
,所以它不是。当您将
x
声明为
final boolean x=false时并有一个内部类/lambda表达式执行
if(x)System.out.println(y)返回
指令,但仍然捕获
y
。不同的问题,但相关的问题是:除了您之外,还有谁会对此进行澄清?