【问题标题】:Are compiled Java 8 lambda expressions backwards compatible with earlier versions of the Java runtime?编译的 Java 8 lambda 表达式是否向后兼容早期版本的 Java 运行时?
【发布时间】:2014-03-22 01:23:24
【问题描述】:

为了减少大量匿名类型实例化造成的混乱,我正在探索利用 Java 8 lambdas 的可能性。

在生产环境中使用 Java 8 和 lambda 之前的一个重要考虑因素是,使用 lambda 表达式的 JDK8 编译代码是否可以在早期版本的 Java 运行时上执行。我对 JRE6 和 JRE7 作为目标平台特别感兴趣。

一方面,我知道 lambda 只是围绕包含一个方法的匿名类的实例化的语法糖。另一方面,我不确定这种等效性是否意味着为每个生成的字节码在 JRE8 以外的 JVM 版本之间是相同和/或兼容的。

例如,给定单方法接口:

public interface Action<T> {
    public void perform(T argument);
}

以下两个 sn-ps 在“功能上”是等效的:

使用 lambda:

final Action<String> y = i -> System.out.println(i);

使用匿名类实例:

final Action<String> y = new Action<String>() {
    @Override
    public void perform(final String i) {
        System.out.println(i);
    }
};

我的具体问题是两种构造的语义等价性是否扩展到它们的编译表示的等价性。此外,如果它们确实可以等效地编译,那么这种等效性是否表明 lambda 表达式的编译形式可以在 Java 运行时的早期版本上托管而无需修改?

【问题讨论】:

  • 可以让 lambdas 在 Java 7 VM 上工作,但官方编译器不这样做。
  • IMO 最好将您的 JRE 升级到 Java 8,而不是尝试使用技巧或 hack 使 lambda 在 JRE6/7 上工作;不仅因为您随后获得了 Java 8 功能,还因为 JRE 6 和 7 已停产,将不再从 Oracle 获得任何免费(安全)更新。
  • 另外,JDK 8 编译器不会将 lambda 转换并编译为匿名类;它使用更有效的表示,因此不需要匿名类。

标签: java lambda backwards-compatibility java-8


【解决方案1】:

一般来说,Javac 编译器不可能使用高于目标 JVM 级别的源级别。因此答案是否定的。

【讨论】:

  • Javac 不支持为较旧的 JVM 编译较新的语言功能。所有以前的版本都是如此,AFAIK 也是 Java 8 的情况。请参阅:stackoverflow.com/questions/18320587/…。一般来说,Javac 不是唯一的编译器,所以有人可能会构建一个支持它的编译器。
  • @user2864740 您所指的帖子讨论了一个完全不同的问题:它声称尽管设置为相同的源级别,但不同版本的 javac 编译器处理代码的方式存在不一致。
  • 感谢您支持您的回答。
  • 除了目标 JVM 级别(实际上是类文件版本)之外,lambdas 还需要 Java 8 中添加的运行时支持,而 Java 7 中没有。
【解决方案2】:

官方没有,但对于非官方的解决方案,您应该查看Retrolambda 项目。它不会向后移植 Collection API 更改,但它可以为您处理 lambda 表达式(和方法引用)。

【讨论】:

  • 进行良好的单元测试并在已处理的类上运行它们。如果 retrolambda 中存在错误,您需要提前了解。
  • 优秀!。正是我想要的。我可以享受用于个人库的 Java 8 功能,知道如果需要 Retrolamba 可以帮助为旧版本做好准备:)
【解决方案3】:

我不这么认为 - 字节码版本不同(我认为是 52)并且 lambda 使用 invokedynamic 并且不会被翻译成匿名类..

【讨论】:

  • Invokedynamic 在 1.7 中也可用。 Lambda 是使用方法引用实现的,这是一个新特性。
【解决方案4】:

Java 8 在接口中引入了默认方法实现的新概念。添加此功能是为了向后兼容,以便可以使用旧接口来利用 Java 8 的 lambda 表达式功能。例如,“List”或“Collection”接口没有“forEach”方法声明。因此,添加这样的方法只会破坏集合框架的实现。 Java 8引入了默认方法,使得List/Collection接口可以有forEach方法的默认实现,实现这些接口的类不需要实现同样的。

public interface vehicle {
  default void print(){
      System.out.println("I am a vehicle!");
                       }
                          }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    相关资源
    最近更新 更多