Java 8 lambda表达式在哪里评估?

时间:2017-11-24 07:35:22

标签: java lambda

lambda表达式是在我们编写它们的地方还是在任何其他Java类中进行评估的?

例如:

Stream<Student> absent =  students.values().stream().filter(s -> !s.present());

传递给filter方法的上述lambda表达式是否会在代码写入的给定类中立即执行,或者在另一个类中执行,并且需要花费更多时间(以纳秒为单位),而不是代码是用Java 8之前的传统编码风格?

4 个答案:

答案 0 :(得分:15)

传递给示例中的filter方法的lambda表达式的主体根本不会被执行,因为filter是一个中间操作,只会执行Stream的{​​{1}}在终端操作中结束,例如collectforEach等......

如果您添加终端操作,例如将Stream的元素收集到List

List<Student> absent =  students.values().stream().filter(s -> !s.present()).collect(Collectors.toList());

将为Stream的每个元素执行lambda表达式的主体,以便终端操作能够生成其输出。

请注意,如果将Predicate接口的匿名类实例或其他实现传递给filter方法而不是lambda表达式,则此行为不会更改。

答案 1 :(得分:14)

编译源代码时,编译器将为您使用的lambda表达式插入BroadcastReceiver字节代码指令。实际的实现(在您的情况下是invokedynamic)将通过Predicate在运行时创建。它运行时甚至不会出现在硬盘上 - 这意味着类在内存中生成,ASM没有.class个文件。例如,匿名类之间存在很大差异 - 当您编译时会生成Predicate文件。

如果您使用以下代码运行示例,则可以看到class生成的文件。

Predicate

否则Eran's answer是正确的,-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here 由终端操作驱动,如果不存在则不执行任何操作。你应该阅读关于更有趣的差异的优秀Holger's answer

答案 2 :(得分:4)

表达式是惰性评估的,这意味着它们实际上只有在你真正尝试终止时才会被评估。流 - 即使用获取流但返回其他内容的操作,如collectminmaxreduce等。将流作为输入的操作并返回一个流,因为输出通常是懒惰的。

答案 3 :(得分:1)

Lambda表达式本质上是具有单个方法的对象,因此只要调用该方法,就会对它们进行求值。

在您的特定情况下,他们从未被评估过。在您调用终止操作(collectfindAny等等)之前,Stream不会评估表达式