Last active
May 28, 2022 16:14
-
-
Save JakeWharton/ea4982e491262639884e to your computer and use it in GitHub Desktop.
A comparison between non-capturing and capturing expressions across Java 6, Java 8, Java 8 with Retrolambda, Kotlin with native function expressions, and Kotlin with Java SAM expression.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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[]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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[]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// '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() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// '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() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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(); | |
} |
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.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@JakeWharton In KotlinFunc_output.txt, on line 4, I guess it should be
public static final NonCapturing$main$1 INSTANCE;
instead ofpublic static final Capturing$main$1 INSTANCE;
.