【问题标题】:Java Lambdas : How it works in JVM & is it OOP? [closed]Java Lambdas:它在 JVM 中是如何工作的?它是面向对象的吗? [关闭]
【发布时间】:2015-03-19 11:49:12
【问题描述】:

例如,在匿名内部类的情况下,传递(匿名)对象引用并执行该对象的方法。

Lambda 是在需要时执行的代码块。

当遇到 lambda 时,JVM 会发生什么? JVM 将 lambdas 相关的代码块存放在哪里(Heap : Young, Old or Permanent Generation)?

我尝试搜索,得到了使用 lambdas 的语法,但无法理解 JVM 内部发生了什么,因为在 JAVA 中一切都是基于对象的。

  1. 那么在 OOP 上下文中,lambda 是如何工作的?

  2. lambda 是否违反 OOP 概念?

  3. Lambda 对垃圾收集器有好处吗,因为没有创建对象 不用担心内存问题和清​​除内存?

【问题讨论】:

  • 我认为 lambdas 是另一种让你的代码更紧凑(或者可能更好)的方法。 OOP 的范式并没有以那种方式触及,但这是我的看法。
  • Lambda 是 函数式编程 的重要组成部分,正如您所知道的 OOP 不同。
  • 从表面上看,lambda 表示法似乎违反了“结构化编程”的一些规则,这是 OOP 的一个(很少提及的)基础。不过,我还没有仔细研究过它,而且 javac 在过去 10 年里已经变成了一大堆非结构化的混乱。
  • 如果我们担心如何在编译器或虚拟机中实现 lambda,难道不应该先对所有这些 goto 进行处理吗?
  • 一个常见的误解是 OOP 和 FP 在某种程度上相互矛盾。但是我们不会因为编写面向对象程序或函数式程序而获得报酬,我们会因为编写工作程序而获得报酬(无论如何,理想情况下)。OOP 和 FP 都为我们提供了包含自然复杂性的工具编程;作为程序员,我们应该尽可能多地从 OOP 和 FP 中学习,并在有助于实现编写工作、可维护、可测试、可读、无错误程序的目标的地方使用他们每个人所教的东西。

标签: java oop lambda jvm java-8


【解决方案1】:

我不会浪费时间去思考 lambda 表达式是否违反了 OO 原则。它的目标是增加语言的能力,而不是编写 OO 代码,我看不出 lambda 会如何违反封装、继承或多态性。

article 解释了 Java 如何处理 lambda 表达式:

Lambda 表达式的有趣之处在于,从 JVM 的角度来看,它们是完全不可见的。它不知道匿名函数或 Lambda 表达式是什么。它只知道字节码,这是一个严格的 OO 规范。语言的制造者及其编译器需要在这些限制内工作,以创建更新、更高级的语言元素。

考虑以下代码:

List names = Arrays.asList("1", "2", "3");
Stream lengths = names.stream().map(name -> name.length());

...它从加载名称 var 并调用其.stream() 方法开始,但随后它做了一些非常优雅的事情。它没有创建将包装 Lambda 函数的新对象,而是使用 Java 7 中添加的新 invokeDynamic 指令将此调用站点动态链接到实际的 Lambda 函数。

aload_1 //load the names var

// call its stream() func
invokeinterface java/util/List.stream:()Ljava/util/stream/Stream;

//invokeDynamic magic!
invokedynamic #0:apply:()Ljava/util/function/Function;

//call the map() func
invokeinterface java/util/stream/Stream.map:
(Ljava/util/function/Function;)Ljava/util/stream/Stream;

InvokeDynamic 是 Java 7 中添加的一条指令,旨在降低 JVM 的严格性,并允许动态语言在运行时绑定符号,而不是在 JVM 编译代码时静态地执行所有链接。

Lambda 代码

aload_0
invokevirtual java/lang/String.length:()
invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
areturn

【讨论】:

  • 这不是答案。它是“嘿,它使用invokedynamic,去google吧”。
  • 这实际上是一个答案,这就是OP接受它的原因。
【解决方案2】:

Lambda 表达式不会被翻译成anonymous inner classes,它们使用Java 7 中引入的invoke dynamic 来执行函数式方法。 Check this out.

他们是否违反OOP?我不认为你应该关心。 Lambda 使您的代码不那么冗长、更容易理解并且“更容易”并行化。这就是你应该关心的。

来自 Brain Goetz 评论:

我们不会因为编写面向对象程序或函数式程序而获得报酬,我们会因编写工作程序而获得报酬。

【讨论】:

  • Afaik lambda 在 一些 的情况下会被翻译成匿名内部类。但这会在运行时由 invokedynamic 引导处理程序发生,该处理程序会找出处理特定 lambda 的最佳策略。
  • @the8472 就这一说法可能被视为正确的观点而言,它仍然是一个负面有用的表征。你最好放弃与内部类的任何联系——这将导致更好的理解。
  • @BrianGoetz,它不应该是 lambdas 的特征,更多的是关于实现细节的挑剔。
  • @the8472:它是一个可能生成的,即使在工厂中它实际上也恰好被称为“内部类”,但是它缺乏普通的各个方面使其与顶级类不同的内部类,“内部”和“外部”类都不包含有关内部类关系的任何信息。
  • 啊,我明白了。我想我对 lambda 工厂中的 innerClass 内容 + 调用堆栈中出现的合成方法感到困惑。谢谢。
【解决方案3】:
  • Lambda 表达式使用invokedynamic 字节码编译。
  • Lambda 实现与特殊的私有方法存储在同一个类文件中。
  • 是否创建对象来调用 lambda 取决于具体情况。在琐碎的情况下,lambda 被转换为常量方法句柄。
  • 要实例化一个 lambda HotSpot,需要创建一个匿名类来实现 lambda 的功能接口。此类不属于任何 ClassLoader。

请参阅 Lambda Expressions JSR 的规范负责人中的 more details

【讨论】:

    猜你喜欢
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-16
    • 1970-01-01
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多