包含 lambda 表达式的代码是否会在较旧的 JVM 上运行,例如,对于 java 1.6?

2022-09-01 21:44:26

Lambdas是在Java8中引入的。包含 lambda 表达式的代码是否会在较旧的 JVM 上运行,例如,对于 java 1.6?我担心二进制兼容性而不是源代码兼容性。这是一个简单的是/否问题。

谢谢。


答案 1

Oracle非常努力地将Java语言JVM字节码语言分开。Java语言规范只说明了包含lambda表达式的程序的含义,它没有说明该程序应该如何编译或解释

这特别意味着 Java 语言规范中没有任何内容禁止 lambda 表达式的编译方式,即生成的代码可以由 Java 6 JVM 执行,但 Java 语言规范中也没有任何内容可以保证这一点。每个Java供应商都可以以他们想要的任何方式对lambda表达式进行编码。(显然,出于务实的原因,大多数人都试图与Oracle非常接近。这样,例如,可以理解Oracle编码的lambda并进行反向工程的调试器/解编译器/工具将自动使用IBM J9 JDK的Java编译器生成的字节码。javac

Oracle JDK附带的编译器使用相当复杂的LambdaMetafactoryMethodHandlesexpalldynamic机制对lambda表达式进行编码。后者只是在Java 7 JVM引入的,因此这意味着Oracles JDK使用的特定编码至少需要Java 7 JVM。但其他编码绝对是可能的,这些复杂的机械都不是真正必要的,它只是一种性能优化。例如,您可以将Lambda表达式编码为内部类,这将一直工作到Java 1.1 JVM - 这毕竟正是我们将“穷人的lambdas”编写到Java 8的方式;这也是lambda的原始提案甚至Java 8的早期预览版如何实现它,毕竟,Java中lambdas的开发甚至早于Java 7和。javacjavacinvokedynamic

有一个名为 RetroLambda 的编译器,它将 Oracle JDK 生成的 Java 8 JVM 字节码(不是 Java 源代码!)编译为 Java 7 JVM 字节码、Java 6 JVM 字节码或 Java 5 JVM 字节码。使用此编译器,您可以生成一个包含字节码的类文件,该文件将在 Java 8 源代码中的任何 Java 5 或更新的 JVM 上运行,这些源代码使用 Java 8 的所有功能。javac


答案 2

简短的回答:视情况而定。

如果你完全局限于Oracle javac和库,答案是:不;原因如下。

Java 字节码包含一个主要版本号。缺省情况下,Java 8 编译器将 java8 放入数据中。任何较旧的JVM都拒绝运行该代码。但是,可以告诉Java 8编译器创建与较旧的JVM兼容的字节码。但是:为了让较旧的JVM执行这种“特殊”类文件,您需要其所有依赖项都可用!

它在那里中断了:Lambdas利用了Java 6中不存在的调用动态字节码指令。除此之外,编译器在编译lambdas时使用了大量的Java库 - 所有这些都是在java 6之后添加的。

因此,即使您设法使用源代码将lambda编译为Java 6字节码 - 该指令也不可用,您也需要提供所有其他类。

但是:正如另一个很好的答案所解释的那样,javac还有其他方法,它允许您在较旧的JVM上使用lambda。

但是:要小心如何花费你的精力。Java 6对于“服务器端java”来说仍然死了。因此,对于像Android这样的平台来说,使用这些替代方案是可以的,但是当您仍然在某个地方运行Oracle Java 6 JVM时,您应该花费精力将该系统升级到当前版本的Java。


推荐