编程语言
首页 > 编程语言> > java-如何在lambda和外部作用域中使用IntelliJ的Evaluate Expression工具?

java-如何在lambda和外部作用域中使用IntelliJ的Evaluate Expression工具?

作者:互联网

这是一个简单的Java 8 lambda示例.

public class Main {
    public static void main(String[] args){
        String outerScope = "outer";
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                String runnableInner = "runnable inner";
                System.out.println("inside runnable: " + outerScope);
                Void avoid = null; //Breakpoint
            }
        };
        Runnable lambda = () -> {
            String lambdaInner = "lambda inner";
            System.out.println("inside lambda: " + outerScope);
            Void avoid = null; //Breakpoint
        };
        runnable.run();
        lambda.run();
    }
}

在可运行范围内,可以使用IntelliJ的“评估表达式”工具来评估是否定义了externalScope.

但是,在lambda范围内,externalScope是未定义的.

这两个打印语句都正确地打印了outerscope的值.

有没有办法解决这个问题?

解决方法:

Lambda表达式被编译为所属类中的综合方法.当我在您的类中运行javap -private -l时,此方法显示为:

private static void lambda$main$0(java.lang.String);
  LineNumberTable:
    line 18: 0
    line 19: 3
    line 20: 28
    line 21: 30
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        3      28     1 lambdaInner   Ljava/lang/String;
       30       1     2 avoid   Ljava/lang/Void;

您在这里可以看到,该方法具有一个参数,该参数将接收outerScope变量的实际捕获值.但是LocalVariableTable并未为其声明名称,这很可能是调试器未显示其运行时值的原因.

具有讽刺意味的是,这意味着如果我们删除LocalVariableTable属性,我们将看到所需的值.例如.使用-g:lines进行编译并在lambda表达式主体内的断点处停止时,Netbeans调试器显示:

args    String  "outer"
Variable information not available, source compiled without -g option           

因此,我们知道看到所有作为参数传递的值的代价是看不到方法内部声明的其他局部变量.

因此,需要一个LocalVariableTable属性,该属性包含捕获值的外部范围变量名称的名称,该问题必须在javac中予以解决,它将为apparently happen in jdk1.8u60.

如果您迫不及待地不想编写修补LocalVariableTable属性的工具,则可以认为综合方法的调用者知道参数值.因此,如果您在堆栈跟踪中向上移动到运行时生成的lambda实例,您将看到所有捕获的值作为实例变量,尽管它们将生成诸如arg $1等的名称.

标签:java-8,intellij-idea,java,lambda
来源: https://codeday.me/bug/20191120/2046862.html