Java8引入了lambda表达式,很多人可能都会误以为lambda表达式只是匿名内部类的一种优雅表达式,两者并无区别,实际上 两者有本质的区别。lambda表达式不是匿名内部类的一种简洁表达方式,除了能让代码更优雅,还可以减少匿名内部类的创建,降低JVM内存占用和回收的开销。
匿名内部类
final CountDownLatch countDownLatch = new CountDownLatch(3);
final SecureRandom random = new SecureRandom();
Future<String> stringFuture1 = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(random.nextInt(10) * 1000);
countDownLatch.countDown();
return "stringFuture1";
}
});
Future<String> stringFuture2 = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(random.nextInt(10) * 1000);
countDownLatch.countDown();
return "stringFuture2";
}
});
Future<String> stringFuture3 = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(random.nextInt(10) * 1000);
countDownLatch.countDown();
return "stringFuture3";
}
});
countDownLatch.await();
System.out.println("匿名内部类的异步任务 都执行完毕.");
System.out.println(stringFuture1.get());
System.out.println(stringFuture2.get());
System.out.println(stringFuture3.get());
executorService.shutdown();
lambda表达式
final CountDownLatch countDownLatch = new CountDownLatch(3);
final SecureRandom random = new SecureRandom();
Future<String> stringFuture1 = executorService.submit(() -> {
Thread.sleep(random.nextInt(10) * 1000);
countDownLatch.countDown();
return "stringFuture1";
});
Future<String> stringFuture2 = executorService.submit(() -> {
Thread.sleep(random.nextInt(10) * 1000);
countDownLatch.countDown();
return "stringFuture2";
});
Future<String> stringFuture3 = executorService.submit(() -> {
Thread.sleep(random.nextInt(10) * 1000);
countDownLatch.countDown();
return "stringFuture3";
});
countDownLatch.await();
System.out.println("lambda表达式的异步任务都执行完毕.");
System.out.println(stringFuture1.get());
System.out.println(stringFuture2.get());
System.out.println(stringFuture3.get());
executorService.shutdown();
咋一看代码,lambda表达式的代码只是匿名内部类代码的一种简化,其实不是的,我们深入到代码编译后的字节码层面去看看。
匿名内部类的字节码
private static anonymousNestClass()V throws java/lang/InterruptedException java/util/concurrent/ExecutionException
L0
LINENUMBER 8 L0
ICONST_3
INVOKESTATIC java/util/concurrent/Executors.newFixedThreadPool (I)Ljava/util/concurrent/ExecutorService;
ASTORE 0
L1
LINENUMBER 9 L1
NEW java/util/concurrent/CountDownLatch
DUP
ICONST_3
INVOKESPECIAL java/util/concurrent/CountDownLatch.<init> (I)V
ASTORE 1
L2
LINENUMBER 10 L2
NEW java/security/SecureRandom
DUP
INVOKESPECIAL java/security/SecureRandom.<init> ()V
ASTORE 2
L3
LINENUMBER 11 L3
ALOAD 0
NEW com/netflix/mock/LambdaTest$1
DUP
ALOAD 2
ALOAD 1
INVOKESPECIAL com/netflix/mock/LambdaTest$1.<init> (Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)V
INVOKEINTERFACE java/util/concurrent/ExecutorService.submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
ASTORE 3
L4
LINENUMBER 19 L4
ALOAD 0
NEW com/netflix/mock/LambdaTest$2
DUP
ALOAD 2
ALOAD 1
INVOKESPECIAL com/netflix/mock/LambdaTest$2.<init> (Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)V
INVOKEINTERFACE java/util/concurrent/ExecutorService.submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
ASTORE 4
L5
LINENUMBER 27 L5
ALOAD 0
NEW com/netflix/mock/LambdaTest$3
DUP
ALOAD 2
ALOAD 1
INVOKESPECIAL com/netflix/mock/LambdaTest$3.<init> (Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)V
INVOKEINTERFACE java/util/concurrent/ExecutorService.submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
ASTORE 5
L6
LINENUMBER 35 L6
ALOAD 1
INVOKEVIRTUAL java/util/concurrent/CountDownLatch.await ()V
L7
LINENUMBER 36 L7
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "\u533f\u540d\u5185\u90e8\u7c7b\u7684\u5f02\u6b65\u4efb\u52a1 \u90fd\u6267\u884c\u5b8c\u6bd5."
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L8
LINENUMBER 37 L8
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEINTERFACE java/util/concurrent/Future.get ()Ljava/lang/Object;
CHECKCAST java/lang/String
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L9
LINENUMBER 38 L9
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 4
INVOKEINTERFACE java/util/concurrent/Future.get ()Ljava/lang/Object;
CHECKCAST java/lang/String
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L10
LINENUMBER 39 L10
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 5
INVOKEINTERFACE java/util/concurrent/Future.get ()Ljava/lang/Object;
CHECKCAST java/lang/String
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L11
LINENUMBER 40 L11
ALOAD 0
INVOKEINTERFACE java/util/concurrent/ExecutorService.shutdown ()V
L12
LINENUMBER 41 L12
RETURN
L13
LOCALVARIABLE executorService Ljava/util/concurrent/ExecutorService; L1 L13 0
LOCALVARIABLE countDownLatch Ljava/util/concurrent/CountDownLatch; L2 L13 1
LOCALVARIABLE random Ljava/security/SecureRandom; L3 L13 2
LOCALVARIABLE stringFuture1 Ljava/util/concurrent/Future; L4 L13 3
// signature Ljava/util/concurrent/Future<Ljava/lang/String;>;
// declaration: java.util.concurrent.Future<java.lang.String>
LOCALVARIABLE stringFuture2 Ljava/util/concurrent/Future; L5 L13 4
// signature Ljava/util/concurrent/Future<Ljava/lang/String;>;
// declaration: java.util.concurrent.Future<java.lang.String>
LOCALVARIABLE stringFuture3 Ljava/util/concurrent/Future; L6 L13 5
// signature Ljava/util/concurrent/Future<Ljava/lang/String;>;
// declaration: java.util.concurrent.Future<java.lang.String>
MAXSTACK = 5
MAXLOCALS = 6
lambda表达式的字节码
private static lambda()V throws java/lang/InterruptedException java/util/concurrent/ExecutionException
L0
LINENUMBER 44 L0
ICONST_3
INVOKESTATIC java/util/concurrent/Executors.newFixedThreadPool (I)Ljava/util/concurrent/ExecutorService;
ASTORE 0
L1
LINENUMBER 45 L1
NEW java/util/concurrent/CountDownLatch
DUP
ICONST_3
INVOKESPECIAL java/util/concurrent/CountDownLatch.<init> (I)V
ASTORE 1
L2
LINENUMBER 46 L2
NEW java/security/SecureRandom
DUP
INVOKESPECIAL java/security/SecureRandom.<init> ()V
ASTORE 2
L3
LINENUMBER 47 L3
ALOAD 0
ALOAD 2
ALOAD 1
INVOKEDYNAMIC call(Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)Ljava/util/concurrent/Callable; [
// handle kind 0x6 : INVOKESTATIC
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
// arguments:
()Ljava/lang/Object;,
// handle kind 0x6 : INVOKESTATIC
com/netflix/mock/LambdaTest.lambda$lambda$0(Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)Ljava/lang/String;,
()Ljava/lang/String;
]
INVOKEINTERFACE java/util/concurrent/ExecutorService.submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
ASTORE 3
L4
LINENUMBER 52 L4
ALOAD 0
ALOAD 2
ALOAD 1
INVOKEDYNAMIC call(Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)Ljava/util/concurrent/Callable; [
// handle kind 0x6 : INVOKESTATIC
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
// arguments:
()Ljava/lang/Object;,
// handle kind 0x6 : INVOKESTATIC
com/netflix/mock/LambdaTest.lambda$lambda$1(Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)Ljava/lang/String;,
()Ljava/lang/String;
]
INVOKEINTERFACE java/util/concurrent/ExecutorService.submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
ASTORE 4
L5
LINENUMBER 57 L5
ALOAD 0
ALOAD 2
ALOAD 1
INVOKEDYNAMIC call(Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)Ljava/util/concurrent/Callable; [
// handle kind 0x6 : INVOKESTATIC
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
// arguments:
()Ljava/lang/Object;,
// handle kind 0x6 : INVOKESTATIC
com/netflix/mock/LambdaTest.lambda$lambda$2(Ljava/security/SecureRandom;Ljava/util/concurrent/CountDownLatch;)Ljava/lang/String;,
()Ljava/lang/String;
]
INVOKEINTERFACE java/util/concurrent/ExecutorService.submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
ASTORE 5
L6
LINENUMBER 62 L6
ALOAD 1
INVOKEVIRTUAL java/util/concurrent/CountDownLatch.await ()V
L7
LINENUMBER 63 L7
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "lambda\u8868\u8fbe\u5f0f\u7684\u5f02\u6b65\u4efb\u52a1\u90fd\u6267\u884c\u5b8c\u6bd5."
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L8
LINENUMBER 64 L8
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEINTERFACE java/util/concurrent/Future.get ()Ljava/lang/Object;
CHECKCAST java/lang/String
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L9
LINENUMBER 65 L9
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 4
INVOKEINTERFACE java/util/concurrent/Future.get ()Ljava/lang/Object;
CHECKCAST java/lang/String
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L10
LINENUMBER 66 L10
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 5
INVOKEINTERFACE java/util/concurrent/Future.get ()Ljava/lang/Object;
CHECKCAST java/lang/String
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L11
LINENUMBER 67 L11
ALOAD 0
INVOKEINTERFACE java/util/concurrent/ExecutorService.shutdown ()V
L12
LINENUMBER 68 L12
RETURN
L13
LOCALVARIABLE executorService Ljava/util/concurrent/ExecutorService; L1 L13 0
LOCALVARIABLE countDownLatch Ljava/util/concurrent/CountDownLatch; L2 L13 1
LOCALVARIABLE random Ljava/security/SecureRandom; L3 L13 2
LOCALVARIABLE stringFuture1 Ljava/util/concurrent/Future; L4 L13 3
// signature Ljava/util/concurrent/Future<Ljava/lang/String;>;
// declaration: java.util.concurrent.Future<java.lang.String>
LOCALVARIABLE stringFuture2 Ljava/util/concurrent/Future; L5 L13 4
// signature Ljava/util/concurrent/Future<Ljava/lang/String;>;
// declaration: java.util.concurrent.Future<java.lang.String>
LOCALVARIABLE stringFuture3 Ljava/util/concurrent/Future; L6 L13 5
// signature Ljava/util/concurrent/Future<Ljava/lang/String;>;
// declaration: java.util.concurrent.Future<java.lang.String>
MAXSTACK = 3
MAXLOCALS = 6
lambda表达式的字节码 很明显多出来了一行关键代码: java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)
LambdaMetafactory的最权威解释: docs.oracle.com/javase/8/do…