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

时间:2017-04-23 07:29:23

标签: java lambda java-8

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

感谢。

3 个答案:

答案 0 :(得分:36)

Oracle非常努力地将Java languageJVM bytecode language分开。 Java语言规范仅says what a program that contains a lambda expression means,它没有提及how this program is supposed to be compiled or interpreted

这意味着Java语言规范中没有任何内容禁止lambda表达式以这样的方式编译,即生成的代码可以由Java 6 JVM执行,但Java语言规范中没有任何内容可以保证它要么。允许每个Java供应商以他们想要的任何方式编码lambda表达式。 (显然,出于实际的原因,大多数尝试匹配Oracle所做的任何事情。例如,可以理解和反向工程由Oracle javac编码的lambdas的调试器/反编译器/工具将自动使用IBM J9 JDK的Java编译器生成的字节码。)

Oracle JDK附带的javac编译器使用LambdaMetafactoryMethodHandlesinvokedynamic的相当复杂的机制对lambda表达式进行编码。后者在introduced中仅为Java 7 JVM,因此这意味着Oracles JDK的javac使用的特定编码至少需要Java 7 JVM。但其他编码绝对是可能的,这些复杂的机器都不是真正必要的,它只是一种性能优化。你可以,例如将Lambda表达式编码为inner classes,这可以归结为Java 1.1 JVM - 这毕竟是我们编写的“穷人的lambdas”到Java 8的结果。这也是lambda的原始提案甚至Java 8的早期预览如何实现它,毕竟,Java早期Java 7和invokedynamic中的lambdas的开发。

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

答案 1 :(得分:16)

简短回答:这取决于。

如果您完全受限于Oracle javac和库,答案是:no;由于以下原因。

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

并且它中断了:Lambdas使用了Java 6中不存在的invokedynamic字节码指令。除此之外,编译器在编译lambda时使用了大量的Java库 - 所有这些都在之后添加java 6。

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

但是:正如另一个伟大的答案所解释的那样,javac还有其他选择,允许你在旧的JVM上使用lambdas。

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

答案 2 :(得分:9)

正如其他人所说:没有

javac编译器生成的类文件是版本化的。 Java 8生成的所有内容都标记为默认需要Java 8 JVM。较旧版本的JVM不接受二进制文件。

如果要编译旧平台,则必须告诉javac:javac -target 6。只要将此选项添加到命令行,Java 8编译器就会要求您指定-source 6(或更低)。因此,它不会接受任何包含lambda表达式的代码。