我在更新调试器以使用
Java 8时遇到一些问题.请考虑以下程序,例如:
public class Lam {
public static void main(String[] args) {
java.util.function.Function<Integer,Integer> square =
x -> {
int result = 0;
for (int i=0;
i<x;
i++)
result++;
return result;
};
System.out.println(square.apply(5));
}
}
如预期的那样,Java 8将lambda编译成如下所示:
> javap -c -p -v -s -constants Lam
Classfile Lam.class
...
private static java.lang.Integer lambda$main$0(java.lang.Integer);
...
Code:
stack=2,locals=3,args_size=1
0: iconst_0
1: istore_1
...
LineNumberTable:
line 5: 0
line 6: 2
line 7: 4
line 9: 12
line 8: 15
line 10: 21
这看起来很像普通的代码.但是,我试图使用Java调试器接口(jdi)来截取程序的每一步.发生错误的第一件事是处理与lambda类相对应的ClassprepareEvent事件.请求event.referenceType()给我一些像Lam $$Lambda $1.1464642111这是很酷.但是,然后在.referenceType()上调用.allLineLocations()给出一个AbsentinformationException,这似乎与编译文件中的LineNumberTable不一致.
它看起来像在Java 8 is possible中跨越lambda体.但是有没有人知道如何在jdi中完成?
更新:
>当在Lam类上调用.allLineLocations时,它会反映所有这些行号.
>当jdi事件发生在lambda类内(例如从步进)时,位置的.sourceName()将抛出一个AbsentinformationException
>它看起来像jdk.internal.org.objectweb.asm.*正在做一些与复制lambda相关的东西
>我不知道从源代码行到字节码的地图是否保存在Java或jdi中
所以我的工作假设是当在运行时创建lambda类时,jdi需要做一些事情来认识到新类的字节码来自旧类的字节码(这又来自于Lam.java).我不知道java.lang.class或com.sun.jdi.Classtype的内部表示,以知道从哪里开始.
为什么我试图这样做:
>更新Java Visualizer与羊羔一起工作
解决方法
您似乎将编译的类与运行时生成的lambda类混淆.后者仅包含将功能界面与编译器类lambda方法中的实现相连接的粘合剂 – 您没有任何要在其中进行任何操作的东西,可能的例外是只有没有源的方法名称. lambda类没有sourceName,因为没有源. ASM代码正在构建生成的lambda类.从字节码位置到源行的映射是在类文件中.