当前java版本为java17
lambda经典写法
先看几个lambda的定义
/// 匿名函数式lambda表达式
Runnable r = () -> {
};
Function<Integer, Integer> func = x -> x + 1;
// 静态方法引用式lambda表达式
BiFunction<HashSet<String>, String, Boolean> func2 = HashSet::add;
Set<String> set = new HashSet<>();
// 实例方法引用式lambda表达式
Function<String, Boolean> func3 = set::add;
// 静态方法引用式lambda表达式; 这里调用的方法直接就是静态方法
Function<Object, Object> f = Objects::requireNonNull;
// lambda的优化
Function<Object, Object> func = Objects::requireNonNull;
Consumer<String> optimizeFunc = Objects::requireNonNull;
// 构造器引用式lambda表达式
// 无参构造
Supplier<List<Integer>> func4 = ArrayList::new;
// 有参构造ArrayList(size)
Function<Integer, List<Integer>> func5 = ArrayList::new;
// lambada表达式实现接口
Function<Student, String> func = (Function<Student, String> & Serializable) Student::getName;
lambda原理探究
说明: 跟着代码debug的时候不要使用@Test注解的方法去跟, 因为它也用了动态语言脚本技术, 直接用main方法测试即可
Runnable r = () -> {}
public class LambdaView {
public static void main(String[] args) {
// 函数式接口
Runnable r = () -> {
};
System.out.println("lambda类的简单类名:" + r.getClass().getSimpleName());
System.out.println("lambda类的名字:" + r.getClass().getName());
System.out.println("lambda类是否为匿名类:" + r.getClass().isAnonymousClass()); // false
// 也可以用 r.getClass().getEnclosingClass() != null 判断是否有外围类
System.out.println("lambda类是否为内部类:" + r.getClass().isMemberClass()); // false
System.out.println("lambda类是否为本地类(局部类):" + r.getClass().isLocalClass()); // false
System.out.println("lambda类是否为隐藏类:" + r.getClass().isHidden()); // true
System.out.println("lambda类是否为动态生成的类:" + r.getClass().isSynthetic()); // true
Runnable r2 = new Runnable() {
@Override
public void run() {
}
};
System.out.println("匿名内部类的简单类名:" + r2.getClass().getSimpleName());
System.out.println("匿名内部类的名字:" + r2.getClass().getName());
System.out.println(r2.getClass().isAnonymousClass()); // true
MyRunnable r3 = new MyRunnable();
System.out.println("常规内部类的简单类名:" + r3.getClass().getSimpleName());
System.out.println(r3.getClass().getName());
System.out.println(r3.getClass().isAnonymousClass()); // false
}
static class MyRunnable implements Runnable {
@Override
public void run() {
}
}
}
输出结果
lambda类的简单类名:LambdaView$$Lambda$14/0x0000000801001208
lambda类的名字:per.qiao.myutils.lambda.LambdaView$$Lambda$14/0x0000000801001208
lambda类是否为匿名类:false
lambda类是否为内部类:false
lambda类是否为本地类(局部类):false
lambda类是否为隐藏类:true
lambda类是否为动态生成的类:true
匿名内部类的简单类名:
匿名内部类的名字:per.qiao.myutils.lambda.LambdaView$1
true
常规内部类的简单类名:MyRunnable
per.qiao.myutils.lambda.LambdaView$MyRunnable
false
我们看到lambda表达式的Runnable r的类名包含了$$Lambda$
, 它既不是内部类
也不是本地类也不是匿名类
, 而是一个隐藏类,一个动态生成的类
接下来我们单独研究这个r
public class LambdaView {
public static void main(String[] args) {
// 函数式接口
Runnable r = () -> {
};
}
}
使用javap -c
查看class文件的字节码
javap -c LambdaView.class
结果如下
public class per.qiao.myutils.lambda.LambdaView {
public per.qiao.myutils.lambda.LambdaView();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokedynamic #7, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
5: astore_1
6: return
}
第一个code部分是LambdaView
类的无参构造部分, 我们重点关注第二个code部分
其中有个invokedynamic
指令, 它是java7中引入的一种动态方法调用指令, 主要是为了支持动态类型语言和脚本语言在JVM上的高效实现。
与传统的 invokevirtual 或 invokestatic 不同,invokedynamic 不直接绑定到特定方法,而是使用引导方法 (bootstrap method) 动态决定调用目标。
Java 中的 lambda 表达式,引导方法通常是 java.lang.invoke.LambdaMetafactory.metafactory 方法。
这里的代码Runnable r = () -> {}
会调用到LambdaMetafactory#metafactory方法
调用链路: JVM => MethodHandleNatives#linkCallSite =>CallSite#makeSite=>BootstrapMethodInvoker.invoke
LambdaMetafactory#metafactory
/**
* 此方法用于动态生成 lambda 表达式实现,并返回一个 CallSite,用于实际调用 lambda 实现的目标。
*
* @param caller 用于查找类和方法的上下文
* @param interfaceMethodName 要实现的接口方法名
* @param factoryType 返回lambda工厂的类型
* @param interfaceMethodType 接口方法的签名
* @param implementation 目标实现的句柄
* @param dynamicMethodType 实际调用的动态方法签名
* @return
* @throws LambdaConversionException
*/
public static CallSite metafactory(MethodHandles.Lookup caller,
String interfaceMethodName,
MethodType factoryType,
MethodType interfaceMethodType,
MethodHandle implementation,
MethodType dynamicMethodType)
throws LambdaConversionException {
AbstractValidatingLambdaMetafactory mf;
mf = new InnerClassLambdaMetafactory(Objects.requireNonNull(caller),
Objects.requireNonNull(factoryType),
Objects.requireNonNull(interfaceMethodName),
Objects.requireNonNull(interfaceMethodType),
Objects.requireNonNull(implementation),
Objects.requireNonNull(dynamicMethodType),
false,
EMPTY_CLASS_ARRAY,
EMPTY_MT_ARRAY);
mf.validateMetafactoryArgs();
return mf.buildCallSite();
}
debug看一下各个参数的值
caller = per.qiao.myutils.lambda.LambdaView
interfaceMethodName=run
factoryType=()Runnable
interfaceMethodType=()void
implementation=MethodHandle()void
dynamicMethodType=()void
这里我们关注一下buildCallSite
方法
@Override
CallSite buildCallSite() throws LambdaConversionException {
final Class<?> innerClass = spinInnerClass();
// .... 省略代码
try {
Object inst = ctrs[0].newInstance();
return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
}
}
private Class<?> spinInnerClass() throws