当我使用Java8的新语法糖迭代一个集合时,比如

myStream.forEach(item -> {
  // do something useful
});

这不等于下面的"旧语法"片段吗?

myStream.forEach(new Consumer<Item>() {
  @Override
  public void accept(Item item) {
    // do something useful
  }
});

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

推荐答案

它是等效的,但不完全相同.简单地说,如果lambda表达式不捕获值,它将是一个在每次调用中重复使用的单例.

这种行为并没有具体说明.JVM在如何实现它方面有很大的自由.目前,Oracle的JVM for each lambda表达式创建(至少)一个实例(即不在不同的相同表达式之间共享实例),但为所有不捕获值的表达式创建单例.

你可以阅读this answer了解更多细节.在那里,我不仅给出了更详细的描述,还测试了代码以观察当前的行为.


Java®语言规范"15.27.4. Run-time Evaluation of Lambda Expressions"一章介绍了这一点

摘要:

这些规则旨在为Java编程语言的实现提供灵活性,具体如下:

  • 无需在每次判断时分配新对象.

  • 由不同的lambda表达式生成的对象不需要属于不同的类(例如,如果主体是相同的).

  • 求值产生的每个对象不需要属于同一个类(例如,捕获的局部变量可能是内联的).

  • 如果"现有实例"可用,则不需要在前面的lambda求值时创建它(例如,它可能是在包含类的初始化期间分配的).

Java相关问答推荐

Java字符串常数池困惑

@从类文件中删除JsonProperty—Java

如何在Java中声明未使用的变量?

使用JdkClientHttpRequestFactory通过Spring RestClient和Wiemock读取时达到EOF

Java中如何根据Font.canDisplay方法对字符串进行分段

基于调车场算法的科学计算器

Jakarta CDI强制bean构造/注册遗留事件侦听器

如何从错误通道回复网关,使其不会挂起

在向WebSphere中的文档添加元素时iText挂起

为什么有两种实现来检索数组类的组件类型?

Spring Boot中的应用程序.properties文件中未使用的属性

如何在Record Java中使用isRecord()和RecordComponent[]?

Maven-Dependency-Plugin 3.6.+开始查找在依赖关系:分析目标期间找到的新的使用的未声明依赖关系

获取所有可以处理Invent.ACTION_MEDIA_BUTTON Android 13 API33的Android包

如何使用带有可选参数的类生成器?

[jdk21][Foreign Function&;Memory API]MemoryLayout::varHandle通过可变数组进行 struct 化的问题

由于版本不匹配,从Java 8迁移到Java 17和Spring 6 JUnit4失败

Java泛型方法重载

try 添加;按流派搜索;在Web应用程序上,但没有;I don’我不知道;It’这个代码错了

始终使用Spring Boot连接mongodb上的测试数据库