2015-02-11 48 views
7

从当前的JDK 1.8实现开始,它构建了一个匿名对象来存放lambda函数并在这个对象上调用函数。这个匿名对象是在每次调用中重用的,还是每次都重新创建一个对象?Java lambda匿名对象是否被重用?

+0

据我记得,lamdas没有编译成对象。相反,它们被翻译成它们被定义的类的方法。 – mkrakhin 2015-02-11 11:35:10

+0

@mkrakhin http://www.lambdafaq.org/are-lambda-expressions-objects/ – 2015-02-11 12:09:46

+0

我找不到链接,但我阅读了一篇文章,告诉我,Oracle工程师决定不实施lambdas作为实例匿名课程。他们告诉我们这种方法会影响性能,因为ClassLoader额外的工作和元空间中的额外占用空间。 – mkrakhin 2015-02-11 12:14:45

回答

2

它可能被重新使用,它可能不会。

JLS 15.27.4

任一类与性质如下 分配和初始化,或与下面的 属性的类的现有实例的新实例被引用。

你不能依赖它是一个或另一个。编译器和/或运行时可以选择能够给出最佳结果的那个。 (这是lambdas与匿名类相比的好处之一 - 因为每次使用new时,即使在匿名类上,它也是一个新对象,它们无法通过重用来优化它,尽管99%的时间你不关心它们是否是同一个对象)

在lambda从周围范围捕获变量的情况下,通常不可能重用对象,因为捕获变量的值是状态存储在lambda对象中的,并且每次计算lambda时(即使它在源代码中是相同的lambda),它都可以捕获捕获变量的不同值。只有编译器能够以某种方式保证对lambda的两个特定评估必须捕获完全相同的变量值时,编译器是否可以重新使用该对象。

在lambda未捕获任何变量的情况下,该lambda的所有实例在行为上都是相同的。所以在这种情况下,单个对象可以重新用于该lambda的所有评估。我相信在这种情况下,Java的当前实现只会在程序期间分配一个副本。但这只是一个依赖于实现的优化。

+0

1.对于周围范围变量捕获,通常对于方法中的变量是正确的;但是我认为如果它引用类的变量,它应该是可重用的。 2.您可以提供一些证据和/或讨论关于可重用性的常见实现和逻辑,例如Oracle JDK和OpenJDK。我知道它可以被重用,但是知道字节码编译器或JIT何时以及如何执行它是很好的。 – 2015-02-12 02:18:06

+0

你也有文档链接说这个实现是JVM特定的,而不是一个标准? – 2015-02-12 02:20:06

+1

@AlexSuoL:1.从某个角度来看,*只有*局部变量可以被“捕获”。我不知道你的意思是“班级变数”。实例变量总是通过某个引用上的成员查找来访问;如果未指定,则隐含地为'this'。 'this'实际上是所有实例方法中的最后一个局部变量,如果使用实例变量或方法,它就像其他局部变量一样在lambdas中捕获。 'this'可以在对方法的不同调用之间改变,所以它需要像其他任何捕获的局部变量一样被存储。静态变量不被“捕获”。 – newacct 2015-02-12 03:27:21