-
-
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" ?