-
-
Save JakeWharton/ea4982e491262639884e to your computer and use it in GitHub Desktop.
| Each respective use has a .class method cost of | |
| Java 6 anonymous class: 2 | |
| Java 8 lambda: 1 | |
| Java 8 lambda with Retrolambda: 6 | |
| Java 8 method reference: 0 | |
| Java 8 method reference with Retrolambda: 5 | |
| Kotlin with Java Runnable expression: 3 (subtract one for non-capturing) | |
| Kotlin with native function expression: 4 (subtract one for non-capturing) | |
| All of them also require an additinal class to be generated (Java 8 defers this to happen at runtime). | |
| (Remember, don't count the methods from `Capturing` / `NonCapturing` or its implicit constructor) |
| import java.util.Arrays; | |
| class NonCapturing { | |
| public static void main(String... args) { | |
| run(new Runnable() { | |
| @Override public void run() { | |
| System.out.println("Hey!"); | |
| } | |
| }); | |
| } | |
| private static void run(Runnable run) { | |
| run.run(); | |
| } | |
| } | |
| class Capturing { | |
| public static void main(final String... args) { | |
| run(new Runnable() { | |
| @Override public void run() { | |
| System.out.println("Hey! " + Arrays.toString(args)); | |
| } | |
| }); | |
| } | |
| private static void run(Runnable run) { | |
| run.run(); | |
| } | |
| } |
| $ javap -p NonCapturing* | |
| Compiled from "Java6.java" | |
| final class NonCapturing$1 implements java.lang.Runnable { | |
| NonCapturing$1(); | |
| public void run(); | |
| } | |
| Compiled from "Java6.java" | |
| class NonCapturing { | |
| NonCapturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| } | |
| $ javap -p Capturing* | |
| Compiled from "Java6.java" | |
| final class Capturing$1 implements java.lang.Runnable { | |
| final java.lang.String[] val$args; | |
| Capturing$1(java.lang.String[]); | |
| public void run(); | |
| } | |
| Compiled from "Java6.java" | |
| class Capturing { | |
| Capturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| } |
| import java.util.Arrays; | |
| class NonCapturing { | |
| public static void main(String... args) { | |
| run(() -> System.out.println("Hey!")); | |
| } | |
| private static void run(Runnable run) { | |
| run.run(); | |
| } | |
| } | |
| class Capturing { | |
| public static void main(String... args) { | |
| run(() -> System.out.println("Hey! " + Arrays.toString(args))); | |
| } | |
| private static void run(Runnable run) { | |
| run.run(); | |
| } | |
| } |
| $ javap -p NonCapturing* | |
| Compiled from "Java8Lambda.java" | |
| class NonCapturing { | |
| NonCapturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| private static void lambda$main$0(); | |
| } | |
| $ javap -p Capturing* | |
| Compiled from "Java8Lambda.java" | |
| class Capturing { | |
| Capturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| private static void lambda$main$1(java.lang.String[]); | |
| } |
| $ javap -p NonCapturing* | |
| final class NonCapturing$$Lambda$1 implements java.lang.Runnable { | |
| private static final NonCapturing$$Lambda$1 instance; | |
| private NonCapturing$$Lambda$1(); | |
| public void run(); | |
| static {}; | |
| public static java.lang.Runnable lambdaFactory$(); | |
| } | |
| Compiled from "Java8Lambda.java" | |
| class NonCapturing { | |
| NonCapturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| private static void lambda$main$0(); | |
| static void access$lambda$0(); | |
| } | |
| $ javap -p Capturing* | |
| final class Capturing$$Lambda$1 implements java.lang.Runnable { | |
| private final java.lang.String[] arg$1; | |
| private Capturing$$Lambda$1(java.lang.String[]); | |
| private static java.lang.Runnable get$Lambda(java.lang.String[]); | |
| public void run(); | |
| public static java.lang.Runnable lambdaFactory$(java.lang.String[]); | |
| } | |
| Compiled from "Java8Lambda.java" | |
| class Capturing { | |
| Capturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| private static void lambda$main$1(java.lang.String[]); | |
| static void access$lambda$0(java.lang.String[]); | |
| } |
| class NonCapturing { | |
| public static void main(String... args) { | |
| run(NonCapturing::sayHi); | |
| } | |
| private static void run(Runnable run) { | |
| run.run(); | |
| } | |
| private static void sayHi() { | |
| System.out.println("Hey!"); | |
| } | |
| } | |
| class Capturing { | |
| public static void main(Capturing instance) { | |
| run(instance::sayHi); | |
| } | |
| private static void run(Runnable run) { | |
| run.run(); | |
| } | |
| void sayHi() { | |
| System.out.println("Hey!"); | |
| } | |
| } |
| $ javap -p NonCapturing* | |
| Compiled from "Java8MethodRef.java" | |
| class NonCapturing { | |
| NonCapturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| private static void sayHi(); | |
| } | |
| $ javap -p Capturing* | |
| Compiled from "Java8MethodRef.java" | |
| class Capturing { | |
| Capturing(); | |
| public static void main(Capturing); | |
| private static void run(java.lang.Runnable); | |
| void sayHi(); | |
| } |
| $ javap -p NonCapturing* | |
| final class NonCapturing$$Lambda$1 implements java.lang.Runnable { | |
| private static final NonCapturing$$Lambda$1 instance; | |
| private NonCapturing$$Lambda$1(); | |
| public void run(); | |
| static {}; | |
| public static java.lang.Runnable lambdaFactory$(); | |
| } | |
| Compiled from "Java8MethodRef.java" | |
| class NonCapturing { | |
| NonCapturing(); | |
| public static void main(java.lang.String...); | |
| private static void run(java.lang.Runnable); | |
| static void sayHi(); | |
| static void access$lambda$0(); | |
| } | |
| $ javap -p Capturing* | |
| final class Capturing$$Lambda$1 implements java.lang.Runnable { | |
| private final Capturing arg$1; | |
| private Capturing$$Lambda$1(Capturing); | |
| private static java.lang.Runnable get$Lambda(Capturing); | |
| public void run(); | |
| public static java.lang.Runnable lambdaFactory$(Capturing); | |
| } | |
| Compiled from "Java8MethodRef.java" | |
| class Capturing { | |
| Capturing(); | |
| public static void main(Capturing); | |
| private static void run(java.lang.Runnable); | |
| void sayHi(); | |
| static void access$lambda$0(Capturing); | |
| } |
| // 'run' is built-in method so we use 'run2' instead. | |
| class NonCapturing { | |
| fun main(vararg args: String) { | |
| run2(Runnable { println("Hey!") }) | |
| } | |
| private fun run2(func: Runnable) { | |
| func.run() | |
| } | |
| } | |
| class Capturing { | |
| fun main(vararg args: String) { | |
| run2(Runnable { println("Hey! $args") }) | |
| } | |
| private fun run2(func: Runnable) { | |
| func.run() | |
| } | |
| } |
| $ javap -p NonCapturing* | |
| Compiled from "KotlinClass.kt" | |
| final class NonCapturing$main$1 implements java.lang.Runnable { | |
| public static final NonCapturing$main$1 INSTANCE; | |
| public final void run(); | |
| NonCapturing$main$1(); | |
| static {}; | |
| } | |
| Compiled from "KotlinClass.kt" | |
| public final class NonCapturing { | |
| public final void main(java.lang.String...); | |
| private final void run2(java.lang.Runnable); | |
| public NonCapturing(); | |
| } | |
| $ javap -p Capturing* | |
| Compiled from "KotlinClass.kt" | |
| final class Capturing$main$1 implements java.lang.Runnable { | |
| final java.lang.String[] $args; | |
| public final void run(); | |
| Capturing$main$1(java.lang.String[]); | |
| } | |
| Compiled from "KotlinClass.kt" | |
| public final class Capturing { | |
| public final void main(java.lang.String...); | |
| private final void run2(java.lang.Runnable); | |
| public Capturing(); | |
| } |
| // 'run' is built-in method so we use 'run2' instead. | |
| class NonCapturing { | |
| fun main(vararg args: String) { | |
| run2({ println("Hey!") }) | |
| } | |
| private fun run2(func: () -> Unit) { | |
| func() | |
| } | |
| } | |
| class Capturing { | |
| fun main(vararg args: String) { | |
| run2({ println("Hey! $args") }) | |
| } | |
| private fun run2(func: () -> Unit) { | |
| func() | |
| } | |
| } |
| $ javap -p NonCapturing* | |
| Compiled from "KotlinFunc.kt" | |
| final class NonCapturing$main$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function0<kotlin.Unit> { | |
| public static final Capturing$main$1 INSTANCE; | |
| public java.lang.Object invoke(); | |
| public final void invoke(); | |
| NonCapturing$main$1(); | |
| static {}; | |
| } | |
| Compiled from "KotlinFunc.kt" | |
| public final class NonCapturing { | |
| public final void main(java.lang.String...); | |
| private final void run2(kotlin.jvm.functions.Function0<kotlin.Unit>); | |
| public NonCapturing(); | |
| } | |
| $ javap -p Capturing* | |
| Compiled from "KotlinFunc.kt" | |
| final class Capturing$main$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function0<kotlin.Unit> { | |
| final java.lang.String[] $args; | |
| public java.lang.Object invoke(); | |
| public final void invoke(); | |
| Capturing$main$1(java.lang.String[]); | |
| } | |
| Compiled from "KotlinFunc.kt" | |
| public final class Capturing { | |
| public final void main(java.lang.String...); | |
| private final void run2(kotlin.jvm.functions.Function0<kotlin.Unit>); | |
| public Capturing(); | |
| } |
@wiibaa Not really. It's code compiled with Java 8 that is then run through the Retrolambda tool. I could have been more clear here, I suppose, but it's Java 8 code not Java 7 code even though the bytecode ends up not being Java 8 but Java 7 compatible.
Great summary. It would be nice to have some up to date numbers for Retrolambda 2.3 (after merging your pull request luontola/retrolambda#81).
Is there a difference between compiling against different minSdkVersion using the new java 8 toolchain e.g. on minSdkVersion < 24 and minSdkVersion >= 24. As on minSdkVersion 24 java 8 feature support seems much more complete, there might also be a difference in generated classes.
A Scala example would be great plus Kotlin 1.1 with -jvm-target 1.8
@JakeWharton In KotlinFunc_output.txt, on line 4, I guess it should be public static final NonCapturing$main$1 INSTANCE; instead of public static final Capturing$main$1 INSTANCE;.
Hi Jake, I have a question
Non-capturing lambda will generate a static instance (singleton) to re-use, so this instance never gets garbage collected? Because it might effect memory footprint.
Sorry for the silly question, but did you want to say "Java Seven with Retrolambda" ?