lambda创建对象java_关于java:lambda表达式每次执行时都会在堆上创建一个对象吗?...

当我使用Java 8的新语法糖遍历集合时,例如

myStream.forEach(item -> {

// do something useful

});

这不等同于下面的"旧语法"代码段吗?

myStream.forEach(new Consumer() {

@Override

public void accept(Item item) {

// do something useful

}

});

这是否意味着每次迭代集合时都会在堆上创建一个新的匿名Consumer对象? 这需要多少堆空间? 它对性能有什么影响? 这是否意味着在遍历大型多级数据结构时,我宁愿使用旧样式的循环?

简短的回答:不。 对于无状态Lambda(那些无法从其词法上下文中捕获任何内容的Lambda),将仅(懒惰地)创建一个实例并将其缓存在捕获站点中。 (这是实现的工作方式;精心编写了规范以允许(但不要求)这种方法。)

infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood

它是等效的但不相同。简而言之,如果lambda表达式未捕获值,则它将是单例,可在每次调用时重复使用。

行为没有完全指定。 JVM被赋予了很大的自由来实现它。目前,Oracle的JVM每个lambda表达式(至少在一个相同的表达式之间不共享实例)(至少)创建一个实例,但为所有不捕获值的表达式创建单例。

您可以阅读此答案以获取更多详细信息。在那里,我不仅给出了更详细的描述,还提供了测试代码以观察当前行为。

这是Java所涵盖的吗?语言规范,第" 15.27.4章"。 Lambda表达式的运行时评估"

总结如下:

These rules are meant to offer flexibility to implementations of the Java programming language, in that:

A new object need not be allocated on every evaluation.

Objects produced by different lambda expressions need not belong to different classes (if the bodies are identical, for example).

Every object produced by evaluation need not belong to the same class (captured local variables might be inlined, for example).

If an"existing instance" is available, it need not have been created at a previous lambda evaluation (it might have been allocated during the enclosing class's initialization, for example).

创建代表lambda的实例时,敏感地取决于lambda身体的确切内容。即,关键因素是lambda从词法环境中捕获的内容。如果它没有捕获创建到创建之间可变的任何状态,则不会在每次进入for-each循环时创建一个实例。相反,将在编译时生成综合方法,并且lambda使用站点将只接收委托给该方法的单例对象。

还要注意,这方面与实现有关,您可以期望HotSpot将来会进行改进和改进,以提高效率。有一些总体计划,例如创建一个没有完整对应类的轻量级对象,该类仅具有足够的信息以转发给单个方法。

这是一篇很好的,可访问的有关该主题的深入文章:

http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood

您正在将新实例传递给forEach方法。每次执行此操作时,都会创建一个新对象,但不会为每次循环迭代创建一个对象。迭代是使用相同的"回调"对象实例在forEach方法内部完成的,直到通过循环完成为止。

因此,循环使用的内存不取决于集合的大小。

Isn't this equivalent to the 'old syntax' snippet?

是。它在非常低的水平上有细微的差异,但我认为您不应该在意它们。 Lamba表达式使用invokedynamic功能而不是匿名类。

您是否有任何指定文件? 它是相当有趣的优化。

谢谢,但是如果我有一个集合的集合,例如在对树数据结构进行深度优先搜索时,该怎么办?

@ A.Rama对不起,我没有看到优化。 无论有无lambda以及有无forEach循环,它都是相同的。

它并不是完全一样,但是在任何时候,每个嵌套级别最多仍需要一个对象,这可以忽略不计。 内循环的每次新迭代都会创建一个新对象,最有可能从外循环捕获当前项目。 这会产生一些GC压力,但仍然没有真正要担心的问题。

@aalku:"每次创建新对象时都这样做":不是根据Holger的回答和Brian Goetz的评论。

@lii你是正确的,但并非总是如此。 如果lambda捕获一个值,则它不是单例,并且全部取决于JVM。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值