【问题标题】:Is there any runtime benefit of using lambda expression in Java? [closed]在 Java 中使用 lambda 表达式有什么运行时的好处吗? [关闭]
【发布时间】:2019-05-30 02:33:35
【问题描述】:

我正在阅读一些关于 Java 8 中提供的 lambda 表达式的博客和答案。

我无法弄清楚,单元 lambda 表达式是否有任何运行时优势?

我从不同的来源复制了以下文本,这让我很困惑。

一个答案是——

"lambdas 不会创建新的范围,它们与 封闭块/环境"

在一个博客中-

“使用 lambda 表达式没有运行时的好处,所以我会 谨慎使用它,因为我不介意多写几行 代码。”

来自另一个博客 -

“还有一个好处 lambda 表达式的顺序和并行执行 通过在方法中传递行为来支持"

所以对我来说有很多困惑。 请帮我解决这个问题,这样我就可以避免在深入研究这些东西之前记住错误的方法。

我已经运行了以下代码,我可以说以下代码中的 lambda 表达式只是替代匿名内部类及其在主线程上运行。

List<Integer> list = new ArrayList<>();
list.add(12);
list.forEach(V -> {
    System.out.println(V);
});

我们是否降低了时间复杂度或空间复杂度?

【问题讨论】:

标签: java lambda java-8


【解决方案1】:

lambdas 不会创建新的范围,它们与封闭的块/环境共享相同的范围”是一个几乎正确的陈述(它们确实创建了一个新的范围,但不是内部类的方式做),但与运行时性能没有任何关系。这与代码的正确性有关。

在匿名内部类中,标识符可以通过词法范围解析,在周围范围中找到匹配项,或者通过继承,在匿名内部类的类层次结构中找到匹配项。此场景中解析标识符的规则比较复杂,容易混淆。

此外,匿名类的主体创建了一个新范围,允许创建与周围上下文的局部变量同名的变量,从而隐藏这些变量。

相比之下,lambda 表达式在编写它们的上下文中的工作方式与其他表达式一样。它们不会从将要转换为的函数接口继承任何成员,它们不能创建新的变量来隐藏现有的局部变量,甚至 @ 987654323@ 和 super 与周围上下文中的含义相同:

JLS§15.27.2. Lambda Body

与出现在匿名类声明中的代码不同,名称的含义和出现在 lambda 主体中的 thissuper 关键字,以及引用声明的可访问性,与周围上下文中的相同(除了lambda 参数引入了新名称)。

因此,当您在同一个块中使用表达式 x.foo(y)() -&gt; x.foo(y) 时,很明显 xy 对于两个表达式来说是否相同 xy,因此,在每种情况下都将是相同的foo 方法,对于匿名内部类,您不能说那么简单,因为您必须首先分析整个内部类及其类型层次结构。

这使得 lambda 表达式非常适合您想要定义本地函数的场景,例如将它作为参数传递给方法,甚至不考虑实际使用的interface。除了定义函数签名之外,接口本身不会影响 lambda 表达式。

但这也意味着可能存在 lambda 表达式无法涵盖的匿名类的用例。但 lambda 表达式的目的并不是作为匿名内部类的通用替代品。


谈到性能或并行处理的简单性,shmosel’s answer 已经说过了。如果不知道我们正在研究的操作/问题以及我们实际比较的解决方案,我们就无法做出这样的笼统陈述。

【讨论】:

    【解决方案2】:

    lambdas 不会创建新的范围,它们与封闭的块/环境共享相同的范围

    我不确定你对这句话的看法。

    使用 lambda 表达式没有运行时优势

    相对于什么? Lambda 可能比匿名类执行得更好,但两者都不会胜过简单的控制流语句。

    通过在方法中传递行为的另一个好处是 lambda 表达式顺序和并行执行支持

    Streams 和 lambdas 支持声明式编程,这使得并行化更易于访问。所以使用 lambdas 可能会间接提高性能。

    【讨论】:

      【解决方案3】:

      匿名内部类被编译成额外的 .class 文件,但 lambda 是动态翻译的。这是一个详细的帖子:How will Java lambda functions be compiled?

      【讨论】:

      • 额外的 .class 文件会对运行时产生任何影响吗?
      • @AmolPatil IMO,这两种方式各有利弊。使用匿名类会创建额外的文件,因此 JVM 必须出去寻找它(然后加载类)。另一方面,因为 lambda 是在运行时解释的,所以解释肯定也会花费一些(我不是专家,但这是我所理解的)。因此,只有在您的目标系统上进行基准测试时,这些才会很明显。
      • 感谢@Jai,但我认为类会在 jvm 午餐时加载,所以我认为额外的 .class 文件不会对运行时产生影响。如果我错了,请清除我。关于 lambdas,我不知道 lambdas 是在运行时解释的
      • @AmolPatil 好吧,.class 文件在启动时或第一次使用时被加载,这已经是一个有影响的操作,即使它只是一次性的。有时,初始化时间是相关的,但当然,对于运行数周的服务器来说,这并不重要。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-18
      • 1970-01-01
      • 2022-11-14
      相关资源
      最近更新 更多