While playing around with Java stack traces today, I noticed something that I had never noticed before: lambda frames do not show up in stack traces!
For instance, consider the following pre-Java 8 example:
public class VisibleLambda {
public static void main(String[] args) {
foo(new Runnable() {
public void run() {
bar();
}
});
}
static void foo(Runnable lambda) {
lambda.run();
}
static void bar() {
throw new RuntimeException();
}
} In the main method, we create an anonymous inner class that implements Runnable and calls bar when run.
The resulting output for this program is as expected:
Exception in thread "main" java.lang.RuntimeException
at VisibleLambda.bar(VisibleLambda.java:15)
at VisibleLambda$1.run(VisibleLambda.java:5)
at VisibleLambda.foo(VisibleLambda.java:11)
at VisibleLambda.main(VisibleLambda.java:3) Checks out: main calls foo, which then calls the Runnable::run method (here implemented by a class automatically named VisibleLambda$1), which then calls bar. So far, so good, and this matched my understanding of how this works together.
But consider now what happens when we switch to using a Java 8 lambda:
public class HiddenLambda {
public static void main(String[] args) {
foo(() -> bar());
}
static void foo(Runnable lambda) {
lambda.run();
}
static void bar() {
throw new RuntimeException();
}
} …and the output is:
Exception in thread "main" java.lang.RuntimeException
at HiddenLambda.bar(HiddenLambda.java:11)
at HiddenLambda.lambda$main$0(HiddenLambda.java:3)
at HiddenLambda.foo(HiddenLambda.java:7)
at HiddenLambda.main(HiddenLambda.java:3) Did you see it? Two interesting things happened here. One is that a new method named lambda$main$0 appeared in the HiddenLambda class. The other is that our Runnable is gone — nowhere on the stack we can see a run method being called, although it is definitely there.
So what’s the lambda$main$0? Using javap -p -c HiddenLambda we can see that it contains the code to our little lambda:
public class HiddenLambda {
private static void lambda$main$0();
Code:
0: invokestatic #7 // Method bar:()V
3: return
} After reading a bit more of the source code, I’ve discovered that behavior can be controlled with command-line options: -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames.
So finally, here it is in action:
$ java -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames HiddenLambda
Exception in thread "main" java.lang.RuntimeException
at HiddenLambda.bar(HiddenLambda.java:11)
at HiddenLambda.lambda$main$0(HiddenLambda.java:3)
at HiddenLambda$$Lambda$1/791452441.run(<Unknown>:1000000)
at HiddenLambda.foo(HiddenLambda.java:7)
at HiddenLambda.main(HiddenLambda.java:3) 
Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.