如何将 IntelliJ 的 Evaluate Expression 工具与 lambda 和外部作用域一起使用?
How to use IntelliJ's Evaluate Expression tool with lambdas and outer scopes?
这是一个简单的 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();
}
}
在 runnable
范围内,可以使用 IntelliJ 的 "Evaluate Expression" 工具来评估 outerScope
是否已定义。
但是,在 lambda
范围内 outerScope
是未定义的。
两个打印语句都正确打印了 outerscope
的值。
有办法解决这个问题吗?
Lambda 表达式被编译成拥有 class 的合成方法。当我运行javap -private -l
和你的class时,这个方法打印为:
private static void lambda$main[=10=](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
属性,你可以考虑合成方法的 caller 知道参数值。因此,如果您在堆栈跟踪中向上移动到 运行time 生成的 lambda 实例,您将看到所有捕获的值作为实例变量,尽管它们将生成诸如 arg
等的名称
这是一个简单的 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();
}
}
在 runnable
范围内,可以使用 IntelliJ 的 "Evaluate Expression" 工具来评估 outerScope
是否已定义。
但是,在 lambda
范围内 outerScope
是未定义的。
两个打印语句都正确打印了 outerscope
的值。
有办法解决这个问题吗?
Lambda 表达式被编译成拥有 class 的合成方法。当我运行javap -private -l
和你的class时,这个方法打印为:
private static void lambda$main[=10=](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
属性,你可以考虑合成方法的 caller 知道参数值。因此,如果您在堆栈跟踪中向上移动到 运行time 生成的 lambda 实例,您将看到所有捕获的值作为实例变量,尽管它们将生成诸如 arg
等的名称