1. 背景
几年前曾经写过一篇Lambda表达式实现机制的分析,现在回头看存在一些错误和疏漏,有误导嫌疑,因此重写一版订正。
平台需求:本文所示代码需要在jdk 15上编译和运行。
2. Lambda表达式的字节码分析
下面代码为一个Lambda表达式的例子
package demo;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public class Test1 {
public void func1(List<Integer> list) {
if (list == null) {
return;
}
var newList = list.stream()
.map(x -> {
System.out.println("in original lambda " + x);
return x + x;
})
.collect(Collectors.toList());
var s = """
oldList = %s
newList = %s
""";
System.out.println(String.format(s, list, newList));
}
public static void main(String[] args) {
var t1 = new Test1();
var list = new LinkedList<Integer>();
list.add(1);
list.add(2);
t1.func1(list);
}
}
使用javap -c -p -v Test1.class反编译,主要字节码如下所示:
public void func1(java.util.List<java.lang.Integer>);
descriptor: (Ljava/util/List;)V
flags: (0x0001) ACC_PUBLIC
Code:
stack=6, locals=4, args_size=2
0: aload_1
1: ifnonnull 5
4: return
5: aload_1
6: invokeinterface #7, 1 // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
11: invokedynamic #13, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
16: invokeinterface #17, 2 // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
21: invokestatic #23 // Method java/util/stream/Collectors.toList:()Ljava/util/stream/Collector;
24: invokeinterface #29, 2 // InterfaceMethod java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
29: checkcast #8 // class java/util/List
32: astore_2
33: ldc #33 // String oldList = %s\n newList = %s\n
35: astore_3
36: getstatic #35 // Field java/lang/System.out:Ljava/io/PrintStream;
39: aload_3
40: iconst_2
41: anewarray #2 // class java/lang/Object
44: dup
45: iconst_0
46: aload_1
47: aastore
48: dup
49: iconst_1
50: aload_2
51: aastore
52: invokestatic #41 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
55: invokevirtual #47 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
58: return
LineNumberTable:
line 9: 0
line 10: 4
line 13: 5
line 14: 16
line 18: 21
line 19: 33
line 23: 36
line 24: 58
LocalVariableTable:
Start Length Slot Name Signature
0 59 0 this Ldemo/Test1;
0 59 1 list Ljava/util/List;
33 26 2 newList Ljava/util/List;
36 23 3 s Ljava/lang/String;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 59 1 list Ljava/util/List<Ljava/lang/Integer;>;
33 26 2 newList Ljava/util/List<Ljava/lang/Integer;>;
StackMapTable: number_of_entries = 1
frame_type = 5 /* same */
Signature: #95 // (Ljava/util/List<Ljava/lang/Integer;>;)V
private static java.lang.Integer lambda$func1$0(java.lang.Integer);
descriptor: (Ljava/lang/Integer;)Ljava/lan