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

use*_*669 20 java lambda java-8

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

谢谢.

Jör*_*tag 36

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

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

javac该附带的Oracle JDK编码使用lambda表达式的一个相当复杂的机械的编译器LambdaMetafactory,MethodHandle小号invokedynamic.后者仅在Java 7 JVM中引入,因此这意味着Oracles JDK 使用的特定编码至少需要Java 7 JVM.但其他编码绝对是可能的,这些复杂的机器都不是真正必要的,它只是一种性能优化.你可以将Lambda Expressions编码为内部类,这可以归结为Java 1.1 JVM - 这毕竟是我们编写的"穷人的lambdas"到Java 8的结果.这也是lambda的原始提案甚至Java 8的早期预览如何实现它,毕竟,Java中lambdas的开发甚至早于Java 7和Java 7 .javacinvokedynamic

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

  • 绝对是更有帮助的答案.我更新了我的更准确,我会尽自己的努力来获得你应得的声誉. (3认同)

Gho*_*ica 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.

  • RetroLambda将Java 8 JVM字节码编译为Java 5/6/7 JVM字节码.它像我们一直做的那样对Lambda表达式进行编码:作为内部类.整个Lambda Factory/Method Handle /`invokedynamic`舞蹈是一种性能优化,仅此而已.lambda的语义绝不是必需的; 毕竟,自Java 1.1以来,我们可以使用SAM接口和内部类来编写"穷人的lambdas". (12认同)
  • Java语言规范中没有任何内容表明Lambdas必须使用`invokedynamic`.这就是一个特定公司的特定版本的特定版本恰好编码它们的方式.实际上,有*不使用`invokedynamic`的Java8 lambda的*实现. (6认同)
  • @GhostCat"移植任意lambdas"可以通过编译时生成的匿名类重写Java 8类文件中的*invokedynamic recipe*来完成.有字节码反向转换器[tools](https://github.com/orfjackal/retrolambda)这样做.早期的JDK 8版本也在编译时生成了匿名类,Android*Jack*/*desugar*工具链也做了同样的事情. (5认同)
  • [retrolambda](https://github.com/orfjackal/retrolambda)在Android平台上非常受欢迎(现在仍然如此),因为新的Android Studio Jack工具链存在很多实际问题,应该在理论上使它多余.它甚至有自己的SO [标签](http://stackoverflow.com/questions/tagged/retrolambda).还有一些半流行的Java 8 backport库在实践中使用它. (4认同)
  • 关于Java 6"死"的公平观点.我希望那是真的.事实上,我知道银行业的一个组织仍然在Sun JVM 6上(这些组织仍然使用像[IDMS](https://en.wikipedia.org/wiki/IDMS)这样的神秘技术和语言.像COBOL).有趣的是Java开发人员不怕在生产中使用retrolambda.对于我工作过的汽车行业的制造商来说也是如此.我担心总有例外:( (2认同)
  • 我希望这些银行能够确保这些系统与所有系统完全隔离.或者也许他们有自己的团队为他们的JVM创建安全修复程序(但可能不是这样).并且,是的,永远不要说永远.我今天也学到了这一点. (2认同)

Mat*_*mer 9

正如其他人所说:不

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

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


归档时间:

查看次数:

1977 次

最近记录:

8 年,7 月 前