本篇文章为你整理了深入理解Lambda表达式(lambda表达式底层原理)的详细内容,包含有lambda表达式的作用与好处 lambda表达式底层原理 lambda表达式的用法 lambda表达式本质是什么 深入理解Lambda表达式,希望能帮助你了解 深入理解Lambda表达式。
本文首先介绍什么是Lambda表达式,然后讲解它的语法规则,接着对Lambda表达式的应用进行举例,最后探讨Lambda表达式的底层实现原理。
Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
——《百度百科》
Java对于Lambda表达式的支持是从JDK8开始的,它来源于数学中的λ演算,是一套关于函数\(f(x)\)定义、输入量、输出量的计算方案,简化了匿名函数的编写,使代码变得简洁。
另外,提到Lambda表达式,就不得不提及函数式编程。
函数式编程
函数式编程,或称函数程序设计、泛函编程(英语:Functional programming),是一种编程范式,它将电脑运算视为函数运算,并且避免使用程序状态以及易变对象。其中,λ演算为该语言最重要的基础。而且,λ演算的函数可以接受函数作为输入参数和输出返回值。
比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。
在函数式编程中,函数是头等对象,意思是说一个函数,既可以作为其它函数的输入参数值,也可以从函数中返回值,被修改或者被分配给一个变量。
——《维基百科》
总结函数式编程的特点:
函数是“头等公民”
可以赋值给变量
可以作为其它函数的参数进行传递
可以作为其它函数的返回值
接下来用一个例子感受一下什么是Lambda表达式。
首先声明一个接口Factory和一个User类。
public interface Factory {
Object getObject();
public class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
@Override
public String toString() {
return "User{" +
"name=" + name + \ +
", age=" + age +
};
按照传统的方式,想要实现Factory接口中的抽象方法,有两种方法:
子类实现接口
匿名内部类
对于第一种方式,代码如下:
public class SubClass implements Factory {
@Override
public Object getObject() {
return new User("tom", 20);
public class Code01_LambdaTest {
public static void main(String[] args) {
// 子类实现接口
Factory factory = new SubClass();
System.out.println("user = " + user);
对于第二种方式,代码如下:
public class Code01_LambdaTest {
public static void main(String[] args) {
// 匿名内部类
Factory factory = new Factory() {
@Override
public Object getObject() {
return new User("John", 18);
System.out.println("user = " + user);
分析上面的代码,发现接口Factory中仅仅只有一个抽象方法,我们的目的是为了获取User类的对象这么一个简单的操作,却需要书写这么多代码,最最核心的其实就是这一句return new User("John", 18),有没有更加简洁的书写方式实现上面的需求呢?
第三种方法,就是我们要介绍的Lambda表达式。请看代码:
public class Code01_LambdaTest {
public static void main(String[] args) {
// lambda表达式
Factory factory = () - new User("Mike", 30);
System.out.println("user = " + user);
通过对比就会发现,代码是多么的简洁高效!
Lambda表达式的语法格式
必须要有一个函数式接口,有且仅有一个抽象方法的接口,要添加注解@FunctionalInterface!
两种语法格式
(parameters) - {statements}
(patameters) - expression
说明如下:
parameters是函数的参数列表
当参数不止一个时,()不可省略,否则可以省略()和类型;
当函数式接口中抽象方法的参数列表的参数类型可以自动推断时,可以省略对应的类型
statements是执行语句
当函数体仅有一个语句,可以省略{},否则不可省略;
expression是表达式
当函数体只有一个表达式,且运算结果匹配返回值类型,可以省略return关键字
- 是使用指定参数去完成某个功能,不可省略
常见的函数式接口
Runnable、Callable
Supplier、Consumer
Comparator
Predicate
Function
Lambda表达式应用举例
注意,以下源码是基于Java17的。
Runnable、Callable接口
Java-多线程:Callable接口和Runnable接口之间的区别
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
package java.util.concurrent;
@FunctionalInterface
public interface Callable V {
V call() throws Exception;
public static void main(String[] args) {
// 使用匿名内部类的方式实现多线程
new Thread(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("线程 " + name + " 已启动!");
}).start();
// 使用Lambda表达式
new Thread(() - {
String name = Thread.currentThread().getName();
System.out.println("Lambda::线程 " + name + " 已启动!");
}).start();
Supplier、Consumer接口
Supplier接口是一个供给型的接口,需要实现get方法。它更像是一个容器,可以用来存储数据,然后可以供其他方法使用。
Consumer接口就是一个消费型的接口,通过传入参数,然后输出值。Consumer是一个接口,并且只要实现一个accept方法,就可以作为一个消费者输出信息。andThen方法的返回值仍为Consumer接口,因此可以持续消费。
package java.util.function;
@FunctionalInterface
public interface Supplier T {
T get();
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer T {
void accept(T t);
default Consumer T andThen(Consumer ? super T after) {
Objects.requireNonNull(after);
return (T t) - { accept(t); after.accept(t); };
对于Supplier供应商接口,我们求数组arr中的最大值。
public static void main(String[] args) {
int[] arr = {1, 5, 7, 9, 2, 4, 6, 8};
// 获取数组的最大值
Supplier Integer supplier = () - {
int max = Integer.MIN_VALUE;
for (int j : arr) {
if (j max) max = j;
return max;
System.out.println(supplier.get());
对于Consumer消费者接口,我们测试持续消费。
public static void consumer(Consumer String first, Consumer String sec) {
first.andThen(sec).accept("Tt");
然后在main方法中,先消费一条消息"hello",接着再消费一条消息"Tt"
public static void main(String[] args) {
Consumer String consumer = msg - System.out.println("msg = " + msg);
consumer.accept("hello");
consumer(
consumer,
s - System.out.println(s.toUpperCase())
程序的运行结果为:
msg = hello
msg = Tt
Comparator接口
Comparator接口是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。Comparator体现了一种策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。
强行对某个对象collection进行整体排序的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set 或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。
当且仅当对于一组元素 S 中的每个 e1 和 e2 而言,c.compare(e1, e2)==0 与 e1.equals(e2) 具有相等的布尔值时,Comparator c 强行对 S 进行的排序才叫做与 equals 一致 的排序。
当使用具有与 equals 不一致的强行排序能力的 Comparator 对有序 set(或有序映射)进行排序时,应该小心谨慎。假定一个带显式 Comparator c 的有序 set(或有序映射)与从 set S 中抽取出来的元素(或键)一起使用。如果 c 强行对 S 进行的排序是与 equals 不一致的,那么有序 set(或有序映射)将是行为“怪异的”。尤其是有序 set(或有序映射)将违背根据 equals 所定义的 set(或映射)的常规协定。
例如,假定使用 Comparator c 将满足 (a.equals(b) c.compare(a, b) != 0) 的两个元素 a 和 b 添加到一个空 TreeSet 中,则第二个 add 操作将返回 true(树 set 的大小将会增加),因为从树 set 的角度来看,a 和 b 是不相等的,即使这与 Set.add 方法的规范相反。
注:通常来说,让Comparator也实现 java.io.Serializable 是一个好主意,因为它们在可序列化的数据结构(像 TreeSet 、TreeMap)中可用作排序方法。为了成功地序列化数据结构,Comparator(如果已提供)必须实现Serializable。
——《官方文档》
这里不得不提Comparable接口:
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。
实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序。实现此接口的可以用作有序映射(实现了SortedMap接口的对象)或有序集合(实现了SortedSet接口的对象)中的元素,无需指定比较器。
建议(虽然不是必需的)最好使自然排序与equals一致。所谓自然排序与equals一致指的是 类A 对于每一个 o1 和 o2 来说,当且仅当 ( o1.compareTo( o2 ) )与 o1.equals( o2 )具有相同的 布尔值 时,类A的自然排序才叫做与equals一致。
——《官方文档》
两个接口有什么区别?
Comparator位于包java.util下,而Comparable位于包java.lang下。
Comparable接口将比较代码写入需要进行比较类的代码中,而Comparator接口在一个独立的类中实现比较。
Comparator接口相对更灵活,因为它跟接口实现的类是耦合在一起的,可以通过更换比较器来改变不同的比较规则。
Comparable接口强制进行自然排序,而Comparator接口不强制进行自然排序,可以指定排序顺序。
package java.util;
import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;
@FunctionalInterface
public interface Comparator T {
int compare(T o1, T o2);
boolean equals(Object obj);
default Comparator T reversed() {
return Collections.reverseOrder(this);
default Comparator T thenComparing(Comparator ? super T other) {
Objects.requireNonNull(other);
return (Comparator T Serializable) (c1, c2) - {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
注意:boolean equals(Object obj);是属于父类Object的,因此它还是函数式接口,仍然只有一个抽象方法int compare(T o1, T o2);。
public static void main(String[] args) {
String[] arr = {"ab", "c", "d", "go", "bee"};
Comparator String comparator = String::compareTo;
comparator = Comparator.reverseOrder();
comparator = (o1, o2) - o2.length() - o1.length();
Arrays.sort(arr, comparator);
System.out.println("arr = " + Arrays.toString(arr));
依次运行的结果:
arr = [ab, bee, c, d, go]
arr = [go, d, c, bee, ab]
arr = [bee, go, ab, d, c]
Predicate接口
Predicate接口主要用于流的筛选。给定一个包含若干项的流,Stream 接口的filter方法传入Predicate 并返回一个新的流,它仅包含满足给定谓词的项。可以使用 lambda 表达式或方法引用来实现boolean test(T t)方法。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate T {
boolean test(T t);
default Predicate T and(Predicate ? super T other) {
Objects.requireNonNull(other);
return (t) - test(t) other.test(t);
default Predicate T negate() {
return (t) - !test(t);
default Predicate T or(Predicate ? super T other) {
Objects.requireNonNull(other);
return (t) - test(t) other.test(t);
static T Predicate T isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object - targetRef.equals(object);
static T Predicate T not(Predicate ? super T target) {
Objects.requireNonNull(target);
return (Predicate T )target.negate();
注意:Predicate接口包含的单一抽象方法为boolean test(T t),它传入一个泛型参数并返回true或 false。
给定一个字符串String str = "Hello the world !";判断是否包含指定的字符。
定义3个方法,分别实现与、或、非的功能。
public static boolean and(Predicate String p1, Predicate String p2, String s) {
return p1.and(p2).test(s);
public static boolean or(Predicate String p1, Predicate String p2, String s) {
return p1.or(p2).test(s);
public static boolean negate(Predicate String p, String s) {
return p.negate().test(s);
然后在main方法中调用
public static void main(String[] args) {
String str = "Hello the world !";
boolean ans;
ans = and(s - s.contains("H"), s - s.contains("w"), str);
ans = or(s - s.contains("A"), s - s.contains("z"), str);
ans = negate(s - s.length() 10, str);
System.out.println("ans = " + ans);
逐一运行,运行结果为:
ans = true
ans = false
ans = true
Function接口
函数式接口(Functional Interface)有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 Lambda 表达式。
Java 8 中提供了一个函数式接口 Function,这个接口表示对一个参数做一些操作然后返回操作之后的值。这个接口的有一个抽象方法 apply,这个方法就是表明对参数做的操作。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function T, R {
R apply(T t);
default V Function V, R compose(Function ? super V, ? extends T before) {
Objects.requireNonNull(before);
return (V v) - apply(before.apply(v));
default V Function T, V andThen(Function ? super R, ? extends V after) {
Objects.requireNonNull(after);
return (T t) - after.apply(apply(t));
static T Function T, T identity() {
return t -
注意:
这里的抽象方法是apply,可以从数学上理解Function接口,即\(f:T \rightarrow R\),输入一个\(T\)可以返回一个\(R\),\(f\)就是定义的一套规则,交由apply执行。
对于andThen方法,它返回一个组合函数,一个函数的输出将作为另一个函数的输入。如果对任一函数的求值引发异常,则将异常抛给组合函数的调用方。
接下来用对多项式进行求导的例子进行演示。
对于多项式\(f(x) = 5x^3 + 2x^2 + x + 6\),定义数组C=[5,2,1,6]表示它的系数。
首先定义一个用于求导数的lambda表达式:
Function Integer[], Integer[] d = x - {
if (x.length == 1) {
return new Integer[]{0};
Integer[] C1 = new Integer[x.length - 1];
for (int i = 0; i x.length - 1; i++) {
C1[i] = x[i] * (x.length - 1 - i);
return C1;
为了方便查看,定义一个打印多项式的方法:
public static void showX(Integer[] C) {
if (C.length == 1) {
System.out.println("f(x) = " + C[0]);
return;
StringBuilder s = new StringBuilder();
int size = C.length - 1;
for (int i = 0; i = size; i++) {
int pow = size - i;
if (C[i] != 0 pow 0) {
if (C[i] != 1) s.append(C[i]);
if (pow == 1) s.append("x");
else s.append("x^").append(pow);
s.append(" + ");
if (C[i] != 0 pow == 0) s.append(C[i]);
System.out.println("f(x) = " + s);
接下来就可以在main方法里进行调用了,我们可以借助Function接口中的apply方法对多项式进行多次求导。
public static void main(String[] args) {
// 求多项式二阶导数
// f(x) = 5x^3 + 2x^2 + x + 6
// 系数 = [5,2,1,6]
// 幂次 = [3,2,1,0]
// 预期系数 = [30,4]
// 预期幂次 = [1,0]
Integer[] C = {5, 2, 1, 6};
showX(C);
// 求一阶导数
Integer[] C1 = d.apply(C);
showX(C1);
// 求二阶导数
Integer[] C2 = d.andThen(d).apply(C);
showX(C2);
// 求三阶导数
Integer[] C3 = d.andThen(d.andThen(d)).apply(C);
showX(C3);
执行结果:
f(x) = 5x^3 + 2x^2 + x + 6
f(x) = 15x^2 + 4x + 1
f(x) = 30x + 4
f(x) = 30
Lambda的底层实现原理剖析
Lambda表达式的本质
它的本质是函数式接口的匿名子类的匿名对象。底层是依赖ASM技术、由匿名内部类实现的,由于Java是面向对象的语言,因此Lambda表达式是一个语法糖,它不能直接执行,需要转换成内部类才可以运行。
编译和运行的过程图
以下面的代码举例:
import java.util.Arrays;
import java.util.List;
public class LambdaPrinciple {
public static void main(String[] args) {
List String list = Arrays.asList("I", "Love", "You");
list.forEach(s - System.out.println(s));
上述代码的编译和运行过程如图1所示:
详细过程分析
通过反编译得到字节码文件,可以分析Lambda表达式的本质。将cfr-0.145.jar包添加到LambdaPrinciple类的编译路径,如图2所示。
执行反编译命令:java -jar cfr-0.145.jar LambdaPrinciple.class --decodelambdas false,如图3所示。
得到反编译的LambdaPrinciple.class
import java.io.PrintStream;
import java.lang.invoke.LambdaMetafactory;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class LambdaPrinciple {
public static void main(String[] args) {
List String list = Arrays.asList("I", "Love", "You");
list.forEach((Consumer String ) LambdaMetafactory.metafactory(
null, null, null,
(Ljava / lang / Object;)V,
lambda$main$0(java.lang.String),
(Ljava / lang / String;)V)());
private static /* synthetic */ void lambda$main$0(String s) {
System.out.println(s);
从上面可以看到,Lambda表达式最终被编译成lambda$main$0静态方法去执行。
接下来找到LambdaMetafactory.java,看下它的metafactory方法
public final class LambdaMetafactory {
// LambdaMetafactory bootstrap methods are startup sensitive, and may be
// special cased in java.lang.invoke.BootstrapMethodInvoker to ensure
// methods are invoked with exact type information to avoid generating
// code for runtime checks. Take care any changes or additions here are
// reflected there as appropriate.
* Facilitates the creation of simple "function objects" that implement one
* or more interfaces by delegation to a provided {@link MethodHandle},
* after appropriate type adaptation and partial evaluation of arguments.
* Typically used as a em bootstrap method /em for {@code invokedynamic}
* call sites, to support the em lambda expression /em and em method
* reference expression /em features of the Java Programming Language.
* p This is the standard, streamlined metafactory; additional flexibility
* is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}.
* A general description of the behavior of this method is provided
* {@link LambdaMetafactory above}.
* p When the target of the {@code CallSite} returned from this method is
* invoked, the resulting function objects are instances of a class which
* implements the interface named by the return type of {@code factoryType},
* declares a method with the name given by {@code interfaceMethodName} and the
* signature given by {@code interfaceMethodType}. It may also override additional
* methods from {@code Object}.
* @param caller Represents a lookup context with the accessibility
* privileges of the caller. Specifically, the lookup context
* must have {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess()
* full privilege access}.
* When used with {@code invokedynamic}, this is stacked
* automatically by the VM.
* @param interfaceMethodName The name of the method to implement. When used with
* {@code invokedynamic}, this is provided by the
* {@code NameAndType} of the {@code InvokeDynamic}
* structure and is stacked automatically by the VM.
* @param factoryType The expected signature of the {@code CallSite}. The
* parameter types represent the types of capture variables;
* the return type is the interface to implement. When
* used with {@code invokedynamic}, this is provided by
* the {@code NameAndType} of the {@code InvokeDynamic}
* structure and is stacked automatically by the VM.
* @param interfaceMethodType Signature and return type of method to be
* implemented by the function object.
* @param implementation A direct method handle describing the implementation
* method which should be called (with suitable adaptation
* of argument types and return types, and with captured
* arguments prepended to the invocation arguments) at
* invocation time.
* @param dynamicMethodType The signature and return type that should
* be enforced dynamically at invocation time.
* In simple use cases this is the same as
* {@code interfaceMethodType}.
* @return a CallSite whose target can be used to perform capture, generating
* instances of the interface named by {@code factoryType}
* @throws LambdaConversionException If {@code caller} does not have full privilege
* access, or if {@code interfaceMethodName} is not a valid JVM
* method name, or if the return type of {@code factoryType} is not
* an interface, or if {@code implementation} is not a direct method
* handle referencing a method or constructor, or if the linkage
* invariants are violated, as defined {@link LambdaMetafactory above}.
* @throws NullPointerException If any argument is {@code null}.
* @throws SecurityException If a security manager is present, and it
* a href="MethodHandles.Lookup.html#secmgr" refuses access /a
* from {@code caller} to the package of {@code implementation}.
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();
接下来看下new InnerClassLambdaMetafactory()的代码,它的作用是创建内部类
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
MethodType factoryType,
String interfaceMethodName,
MethodType interfaceMethodType,
MethodHandle implementation,
MethodType dynamicMethodType,
boolean isSerializable,
Class ? [] altInterfaces,
MethodType[] altMethods)
throws LambdaConversionException {
super(caller, factoryType, interfaceMethodName, interfaceMethodType,
implementation, dynamicMethodType,
isSerializable, altInterfaces, altMethods);
implMethodClassName = implClass.getName().replace(., /);
implMethodName = implInfo.getName();
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
constructorType = factoryType.changeReturnType(Void.TYPE);
lambdaClassName = lambdaClassName(targetClass);
// If the target class invokes a protected method inherited from a
// superclass in a different package, or does invokespecial, the
// lambda class has no access to the resolved method. Instead, we need
// to pass the live implementation method handle to the proxy class
// to invoke directly. (javac prefers to avoid this situation by
// generating bridges in the target class)
useImplMethodHandle = (Modifier.isProtected(implInfo.getModifiers())
!VerifyAccess.isSamePackage(targetClass, implInfo.getDeclaringClass()))
implKind == H_INVOKESPECIAL;
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
int parameterCount = factoryType.parameterCount();
if (parameterCount 0) {
argNames = new String[parameterCount];
argDescs = new String[parameterCount];
for (int i = 0; i parameterCount; i++) {
argNames[i] = "arg$" + (i + 1);
argDescs[i] = BytecodeDescriptor.unparse(factoryType.parameterType(i));
} else {
argNames = argDescs = EMPTY_STRING_ARRAY;
值得注意的是cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);,它的作用是构造一个新的ClassWriter对象,写字节码文件,这其实就是ASM技术。
回到LambdaMetafactory.java,查看metafactory方法它的返回值,走到这一步时,其实准备工作已经完成了,关键的代码是final Class ? innerClass = spinInnerClass();要返回内部类的字节码文件。
@Override
CallSite buildCallSite() throws LambdaConversionException {
final Class ? innerClass = spinInnerClass();
if (factoryType.parameterCount() == 0) {
// In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance,
// unless weve suppressed eager initialization
if (disableEagerInitialization) {
try {
return new ConstantCallSite(caller.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD,
factoryType.returnType()));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException(
"Exception finding " + LAMBDA_INSTANCE_FIELD + " static field", e);
} else {
@SuppressWarnings("removal")
final Constructor ? [] ctrs = AccessController.doPrivileged(
new PrivilegedAction () {
@Override
public Constructor ? [] run() {
Constructor ? [] ctrs = innerClass.getDeclaredConstructors();
if (ctrs.length == 1) {
// The lambda implementing inner class constructor is private, set
// it accessible (by us) before creating the constant sole instance
ctrs[0].setAccessible(true);
return ctrs;
if (ctrs.length != 1) {
throw new LambdaConversionException("Expected one lambda constructor for "
+ innerClass.getCanonicalName() + ", got " + ctrs.length);
try {
Object inst = ctrs[0].newInstance();
return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception instantiating lambda object", e);
} else {
try {
MethodHandle mh = caller.findConstructor(innerClass, constructorType);
return new ConstantCallSite(mh.asType(factoryType));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception finding constructor", e);
接下来查看spinInnerClass的源码
private Class ? spinInnerClass() throws LambdaConversionException {
// CDS does not handle disableEagerInitialization.
if (!disableEagerInitialization) {
// include lambda proxy class in CDS archive at dump time
if (CDS.isDumpingArchive()) {
Class ? innerClass = generateInnerClass();
LambdaProxyClassArchive.register(targetClass,
interfaceMethodName,
factoryType,
interfaceMethodType,
implementation,
dynamicMethodType,
isSerializable,
altInterfaces,
altMethods,
innerClass);
return innerClass;
// load from CDS archive if present
Class ? innerClass = LambdaProxyClassArchive.find(targetClass,
interfaceMethodName,
factoryType,
interfaceMethodType,
implementation,
dynamicMethodType,
isSerializable,
altInterfaces,
altMethods);
if (innerClass != null) return innerClass;
return generateInnerClass();
接下来查看generateInnerClass()的源码
private Class ? generateInnerClass() throws LambdaConversionException {
String[] interfaceNames;
String interfaceName = interfaceClass.getName().replace(., /);
boolean accidentallySerializable = !isSerializable Serializable.class.isAssignableFrom(interfaceClass);
if (altInterfaces.length == 0) {
interfaceNames = new String[]{interfaceName};
} else {
// Assure no duplicate interfaces (ClassFormatError)
Set String itfs = new LinkedHashSet (altInterfaces.length + 1);
itfs.add(interfaceName);
for (Class ? i : altInterfaces) {
itfs.add(i.getName().replace(., /));
accidentallySerializable = !isSerializable Serializable.class.isAssignableFrom(i);
interfaceNames = itfs.toArray(new String[itfs.size()]);
cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
lambdaClassName, null,
JAVA_LANG_OBJECT, interfaceNames);
// Generate final fields to be filled in by constructor
for (int i = 0; i argDescs.length; i++) {
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
argNames[i],
argDescs[i],
null, null);
fv.visitEnd();
generateConstructor();
if (factoryType.parameterCount() == 0 disableEagerInitialization) {
generateClassInitializer();
// Forward the SAM method
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
interfaceMethodType.toMethodDescriptorString(), null, null);
new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
// Forward the altMethods
if (altMethods != null) {
for (MethodType mt : altMethods) {
mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
mt.toMethodDescriptorString(), null, null);
new ForwardingMethodGenerator(mv).generate(mt);
if (isSerializable)
generateSerializationFriendlyMethods();
else if (accidentallySerializable)
generateSerializationHostileMethods();
cw.visitEnd();
// Define the generated class in this VM.
final byte[] classBytes = cw.toByteArray();
// If requested, dump out to a file for debugging purposes
if (dumper != null) {
AccessController.doPrivileged(new PrivilegedAction () {
@Override
public Void run() {
dumper.dumpClass(lambdaClassName, classBytes);
return null;
}, null,
new FilePermission(" ALL FILES ", "read, write"),
// createDirectories may need it
new PropertyPermission("user.dir", "read"));
try {
// this class is linked at the indy callsite; so define a hidden nestmate
Lookup lookup;
if (useImplMethodHandle) {
lookup = caller.defineHiddenClassWithClassData(classBytes, implementation, !disableEagerInitialization,
NESTMATE, STRONG);
} else {
lookup = caller.defineHiddenClass(classBytes, !disableEagerInitialization, NESTMATE, STRONG);
return lookup.lookupClass();
} catch (IllegalAccessException e) {
throw new LambdaConversionException("Exception defining lambda proxy class", e);
} catch (Throwable t) {
throw new InternalError(t);
这里要注意的是dumper,如果请求,转储到文件以进行调试,点进去,可以得到下面的JVM参数:final String dumpProxyClassesKey = "jdk.internal.lambda.dumpProxyClasses";。
然后在LambdaPrinciple字节码文件所在的路径,继续反编译,将内部类转储出来。
转储命令为:java -Djdk.internal.lambda.dumpProxyClasses LambdaPrincipl。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。