Skip to content

Instantly share code, notes, and snippets.

@javajosh
Last active August 29, 2015 14:21
Show Gist options
  • Save javajosh/55339742aad2f1a1b881 to your computer and use it in GitHub Desktop.
Save javajosh/55339742aad2f1a1b881 to your computer and use it in GitHub Desktop.
Java Lambdas and The Case of the Missing imul

Java Lambdas and The Case of the Missing imul

So at last night's SBJUG meeting the question arose as to the implementation of Java 8 Lambdas, and I answered incorrectly that they were implemented as anonymous inner classes. This was clearly wrong because javac was not emitting any extra class files. Some perusing with javap didn't shed light on the mystery - in fact, only making it deeper.

Watching Brian Goetz's excellent Java Lambdas: A Peek Under the Hood made it clear that something funny was going on. In fact, what is happening is that javac is generating a synthetic method containing the body of the lambda (plus parameters that implement captured variables) and then using invokedynamic and something called a "bootstrap method" to construct an object that uses that method to satisfy the constraints of the invocation. LambdaMetafactory has something to do with this machinery.

The reason we did not see the imul operator was a mistake using javap - in fact, all we needed was to add the -p option, which shows 'private' byte code. This in turn shows the generated method, lambda$main$0() in the above javap output!

As an added bonus, I discovered that lambdas which do not capture variables are quite a lot faster than ones that do (~20x). So that should make a good demo.

//javap -c -p Foo.class
Compiled from "Foo.java"
class Foo {
Foo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
5: astore_1
6: aload_1
7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V
12: return
private static void lambda$main$0();
Code:
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #5 // String hello
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
class Foo{
public static void main(String args[]){
Runnable r = () -> System.out.println("hello");
r.run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment