Java 为什么lambda调用有两个堆栈帧?

Java 为什么lambda调用有两个堆栈帧?,java,lambda,java-8,Java,Lambda,Java 8,以下代码: public static void main(String[] args) { Collections.singleton(1).stream().forEach(i -> new Exception().printStackTrace()); } 印刷品: java.lang.Exception at PrintLambdaStackTrace.lambda$main$0(PrintLambdaStackTrace.java:6) at Print

以下代码:

public static void main(String[] args) {
    Collections.singleton(1).stream().forEach(i -> new Exception().printStackTrace());
}
印刷品:

java.lang.Exception
    at PrintLambdaStackTrace.lambda$main$0(PrintLambdaStackTrace.java:6)
    at PrintLambdaStackTrace$$Lambda$1/1831932724.accept(Unknown Source)
    at java.util.Collections$2.tryAdvance(Collections.java:4717)
    at java.util.Collections$2.forEachRemaining(Collections.java:4725)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at PrintLambdaStackTrace.main(PrintLambdaStackTrace.java:6)
lambda调用是如何实现的?为什么有两个堆栈帧

PrintLambdaStackTrace$$Lambda$1/1831932724.accept(Unknown Source)
这是一个生成的类,它实现了所需的接口。它的
accept
方法只是一个存根,委托给编译时生成并添加到
PrintLambdaStackTrace
类的方法。此类在lambda链接时生成(第一次需要创建lambda实例)


这就是实际实现lambda行为的方法。它属于
PrintLambdaStackTrace
类。

这是个好问题。因为我自己对答案感兴趣,所以我会关注。我的猜测是JVM在执行时创建了一个匿名类。一个堆栈来自用于创建类的方法,第二个堆栈来自类本身。但这只是一个猜测。看,我也不会称之为内部类。它只是一个生成的类。@Bogdan Calmac:实现方法驻留在定义lambda表达式的类中,因此,自然可以访问周围的类。此外,磁盘上/jar文件中没有其他类文件……是的,静态生成代码的开销更小。在将来的实现中,运行时甚至可能不需要生成实现接口的完整类。@Marko Topolnik:好吧,除了这个事实之外,对lambda类来说,唯一区别内部类和普通类的东西,就是对外部实例的引用,并不是强制性的。如果您通过反射请求外部类型,它不会告诉您……好吧,所有实例化都发生在运行时(我想这是可以理解的)。JVM做到了这一点,它涉及
invokedynamic
机制。
PrintLambdaStackTrace.lambda$main$0(PrintLambdaStackTrace.java:6)