lambda表达式是在我们编写它们的位置还是在Java的其他任何类中进行评估?
例如:
Stream<Student> absent = students.values().stream().filter(s -> !s.present());
传递给filter方法的上述lambda表达式将立即在编写代码的给定类中执行吗?还是在另一个类中执行并且需要比如果使用Java 8之前的传统代码风格编写代码需要更多的时间(以纳秒计)?
当你编译源代码时,编译器会为使用的 lambda 表达式插入一个 invokedynamic
字节码指令。实际的实现(在你的情况下是一个 Predicate
)将通过 ASM
在运行时创建。当你运行程序时,它甚至不会存在于硬盘上 - 这意味着类是在内存中生成的,没有 .class
文件来表示 Predicate
。这是与匿名类之间的一个重要区别 - 后者在编译时会生成一个 class
文件。
如果你使用以下命令运行示例,可以看到为 Predicate
生成的文件:
-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
否则Eran的答案是正确的,Stream
是由终端操作驱动的,如果没有这样的操作,就不会执行任何操作。你应该一定要阅读优秀的Holger的答案,了解更有趣的差异。filter
是一个中间操作,只有在以终端操作(例如collect
、forEach
等)结束的Stream
上才会执行。Stream
的元素收集到List
中:List<Student> absent = students.values().stream().filter(s -> !s.present()).collect(Collectors.toList());
lambda表达式的主体将为您的Stream
中的每个元素执行,以便终端操作能够生成其输出。
请注意,如果您将匿名类实例或其他Predicate
接口的实现传递给filter
方法而不是lambda表达式,则此行为不会更改。
collect
, min
, max
, reduce
等返回其他内容而不是流的操作。那些以流作为输入并返回流作为输出的操作通常都是惰性的。collect
、findAny
等)。
s
的值将是什么? - Oliver Charlesworth