Java Lambdas:它在 JVM 中是如何工作的?它是 OOP 吗?
Java Lambdas : How it works in JVM & is it OOP?
例如,在匿名内部 class 的情况下,传递(匿名)对象引用并执行该对象的方法。
Lambda 是将在需要时执行的代码块。
当遇到 lambda 时,JVM 会发生什么? JVM 在哪里存储与 lambdas 相关的代码块(堆:年轻代、老代或永久代)?
我尝试搜索,得到了使用 lambda 的语法,但无法理解 JVM 内部发生的事情,因为 JAVA 一切都是基于对象的。
那么在 OOP 的上下文中,lambda 是如何工作的?
lambda 是否违反 OOP 概念?
Lambda 是否适合垃圾收集器,因为不会创建任何对象
不用担心内存问题和清理内存?
Lambda 表达式不会被翻译成 anonymous inner classes
,它们使用 invoke dynamic that was introduced in Java 7 to execute functional methods. Check this out.
他们是否违反了OOP
?我认为你不应该关心。 Lambda 使您的代码不那么冗长、更容易理解,并且 "easier" 可以并行化。这就是你应该关心的。
来自 Brain Goetz 评论:
We don't get paid to write object-oriented programs or functional programs, we get paid to write working programs.
- Lambda 表达式是使用
invokedynamic
字节码编译的。
- Lambda 实现与特殊私有方法存储在同一个 class 文件中。
- 是否创建对象来调用lambda,视情况而定。在微不足道的情况下,lambda 被转换为常量方法句柄。
- 要实例化 lambda HotSpot,需要创建一个实现 lambda 功能接口的匿名 class。此 class 不属于任何 ClassLoader。
参见more details from the specification lead of Lambda Expressions JSR。
我不会浪费时间思考 lambda 表达式是否违反了 OO 原则。它的目标是增强语言的能力而不是编写 OO 代码,我看不出 lambda 怎么会违反封装、继承或多态性。
此 article 解释了 Java 如何处理 lambda 表达式:
What’s interesting about Lambda expressions is that from the JVM’s perspective they’re completely invisible. It has no notion of what an anonymous function or a Lambda expression is. It only knows bytecode which is a strict OO specification. It’s up to the makers of the language and its compiler to work within these constraints to create newer, more advanced language elements.
考虑以下代码:
List names = Arrays.asList("1", "2", "3");
Stream lengths = names.stream().map(name -> name.length());
... It begins quite simply by loading the names var and invokes its .stream()
method, but then it does something quite elegant. Instead of creating a new object that will wrap the Lambda function, it uses the new invokeDynamic
instruction which was added in Java 7 to dynamically link this call site to the actual Lambda function.
aload_1 //load the names var
// call its stream() func
invokeinterface java/util/List.stream:()Ljava/util/stream/Stream;
//invokeDynamic magic!
invokedynamic #0:apply:()Ljava/util/function/Function;
//call the map() func
invokeinterface java/util/stream/Stream.map:
(Ljava/util/function/Function;)Ljava/util/stream/Stream;
InvokeDynamic
is an instruction that was added in Java 7 to make the JVM less strict, and allows dynamic languages to bind symbols at run-time, vs. doing all the linkage statically when the code is compiled by the JVM.
Lambda 代码
aload_0
invokevirtual java/lang/String.length:()
invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
areturn
例如,在匿名内部 class 的情况下,传递(匿名)对象引用并执行该对象的方法。
Lambda 是将在需要时执行的代码块。
当遇到 lambda 时,JVM 会发生什么? JVM 在哪里存储与 lambdas 相关的代码块(堆:年轻代、老代或永久代)?
我尝试搜索,得到了使用 lambda 的语法,但无法理解 JVM 内部发生的事情,因为 JAVA 一切都是基于对象的。
那么在 OOP 的上下文中,lambda 是如何工作的?
lambda 是否违反 OOP 概念?
Lambda 是否适合垃圾收集器,因为不会创建任何对象 不用担心内存问题和清理内存?
Lambda 表达式不会被翻译成 anonymous inner classes
,它们使用 invoke dynamic that was introduced in Java 7 to execute functional methods. Check this out.
他们是否违反了OOP
?我认为你不应该关心。 Lambda 使您的代码不那么冗长、更容易理解,并且 "easier" 可以并行化。这就是你应该关心的。
来自 Brain Goetz 评论:
We don't get paid to write object-oriented programs or functional programs, we get paid to write working programs.
- Lambda 表达式是使用
invokedynamic
字节码编译的。 - Lambda 实现与特殊私有方法存储在同一个 class 文件中。
- 是否创建对象来调用lambda,视情况而定。在微不足道的情况下,lambda 被转换为常量方法句柄。
- 要实例化 lambda HotSpot,需要创建一个实现 lambda 功能接口的匿名 class。此 class 不属于任何 ClassLoader。
参见more details from the specification lead of Lambda Expressions JSR。
我不会浪费时间思考 lambda 表达式是否违反了 OO 原则。它的目标是增强语言的能力而不是编写 OO 代码,我看不出 lambda 怎么会违反封装、继承或多态性。
此 article 解释了 Java 如何处理 lambda 表达式:
What’s interesting about Lambda expressions is that from the JVM’s perspective they’re completely invisible. It has no notion of what an anonymous function or a Lambda expression is. It only knows bytecode which is a strict OO specification. It’s up to the makers of the language and its compiler to work within these constraints to create newer, more advanced language elements.
考虑以下代码:
List names = Arrays.asList("1", "2", "3");
Stream lengths = names.stream().map(name -> name.length());
... It begins quite simply by loading the names var and invokes its
.stream()
method, but then it does something quite elegant. Instead of creating a new object that will wrap the Lambda function, it uses the newinvokeDynamic
instruction which was added in Java 7 to dynamically link this call site to the actual Lambda function.
aload_1 //load the names var
// call its stream() func
invokeinterface java/util/List.stream:()Ljava/util/stream/Stream;
//invokeDynamic magic!
invokedynamic #0:apply:()Ljava/util/function/Function;
//call the map() func
invokeinterface java/util/stream/Stream.map:
(Ljava/util/function/Function;)Ljava/util/stream/Stream;
InvokeDynamic
is an instruction that was added in Java 7 to make the JVM less strict, and allows dynamic languages to bind symbols at run-time, vs. doing all the linkage statically when the code is compiled by the JVM.
Lambda 代码
aload_0
invokevirtual java/lang/String.length:()
invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
areturn