Categories
程式開發

五年过去了,再看Java缺失的特性


本文要点:

  • 在过去的五年中,Java语言发生了显著的变化
  • 正在实现这一变化的有两个主要的项目:Valhalla和Amber,它们仍在进行中
  • Java继续保持其向后兼容的核心价值
  • 尽管已经25岁了,但Java在语言和平台上仍然具有很强的生命力
  • 诸如Graal之类的新技术正在帮助Java继续保持在编程语言的前沿上

大约是五年前,我写了一篇文章,概述了其他语言的一些特性思想,我认为这些思想可能会对Java有好处。从那以后发生了很多事情:那时,Java 8是最新的发布版本,而现在,最新的版本是Java 14。

让我们依次查看下每个特性,看看它的当前状态是什么:它是已经被添加到Java中了,还是正在开发中,亦或是当前尚没有将其纳入Java的计划。

具体化泛型

我最初的预测排除了具体化泛型(reified generics)。我没有预见到Valhalla项目对从头开始重构JVM的雄心壮志。

Valhalla项目的主要目标是:

  • 使JVM内存布局行为与现代硬件的成本模型保持一致;
  • 扩展泛型,以允许对所有类型(包括原语、值、甚至void)进行抽象;以及
  • 使现有的库(尤其是JDK)能够兼容地演变,以充分利用这些特性。

在此描述中隐藏的是已加载的单词“values”,它已经演变成我们今天称之为内联类的特性。

因此,具体化泛型和原语专业化已经被包含到一个更大的项目中了,该项目承诺从根本上改变Java的编写和执行方式。

尽管正在进行深层次的底层变更,但项目团队的目标包括最大程度地减少对现有Java应用程序的破坏,并为在自己的代码中使用Valhalla功能的开发人员提供一种简单的、可选的方法。

我们应该注意到,Valhalla在很大程度上仍然是一项正在进行的项目,而且尚无关于其何时交付的正式路线图。

判决:正在进行中(作为Valhalla项目的一部分)

无符号算术

在Java的历史上已经反复讨论过支持该特性的可能性了,但是引入该特性的过程涉及到了许多复杂性。

例如,有这样一个问题,即在Java类型系统中如何表示有符号性,以及它是否应该在JVM字节码级别上可见。

这些问题尚未达成任何令人满意的共识,因此,Java仍然不包含无符号算术,而Valhalla项目的一个显著方面是:它不包含对无符号算术的支持。

判决:尚不予考虑

数组long型索引

Java数组的大小受到其设计的一个简单事实的限制:它们是以int作为索引的。这意味着一个数组被限制为2^31个元素(记住int是有符号的),即大约20亿个条目。

正如最初所设想的那样,使用long而不是int的想法将能允许开发人员创建和操纵更大的数组。然而,自从发表最初的“缺失特性”一文以来,社区在此领域的关注点已经转移到提供对堆外存储的大型数组的便捷访问上了。

造成这种情况的原因有很多。易于与非Java库(包括机器学习和其他大量的应用程序)进行互操作是一个重要原因。然而,大型的堆数组到底有多大用处,这也是一个问题。在进出Java堆时,庞大的、具有多个千兆位的数组将会产生巨大的复制成本,并可能会给JVM的垃圾收集器造成严重的困扰。

由于这些原因,在堆外支持的背景下,才会考虑大型数组,并且该概念已被纳入Panama项目中了,该特性正在积极地开发中。

判决:正在进行中(作为Panama项目的一部分)

更具表现力的导入语法

即使在局部(或文件作用域)级别,也没有认真尝试扩展导入语法的作用域或引入类型别名。

判决:尚不予考虑

集合字面量

在Java 9中添加了接口上的静态方法,并且对集合进行了更新,以包括用于集合的工厂方法。它们在Java中扮演集合字面量(Collection Literals)的角色:

var ls = List.of(1,2,3);

由于工厂扮演字面量的角色时,此变更还引入了集合接口的新实现。这些实现是不可变的,因为重用现有的可变集合(例如ArrayList)将违反程序员的期望,即这些值应该表现得像字面量一样。

更具侵入性的解决方案,例如将新字面量直接引入到语言语法中,则不予采用。

判决:已交付(作为工厂方法)

代数数据类型

Java中的代数数据类型(Algebraic Data Type)正在交付中。该特性包括对类型系统的两个主要补充:记录(Records)和密封类型(Sealed Types)以及模式匹配,这是一种非常重要的新语法。

Java 14提供了这两个方面的预览版,具体来说是:记录(Records),在Java中本质上是命名元组;以及模式匹配的初始组件。

组成模式匹配介绍部分的新特性是Java的首个模式形式:instanceof模式switch表达式的标准化版本。

第二个是脚手架(Scaffolding),它将最终支持通用模式匹配的引入,可能会以类似Scala程序员所熟悉的匹配表达式的方式引入。

在该特性完全交付之前,还有许多步骤需要执行:记录和模式仍然只是处于预览状态。因此,需要进一步的JEP(包括JEP 375,它扩展了instanceof模式来析构记录)来充实整个模式匹配。

随着Java 14的到来,关键的JEP(包括JEP 375和JEP 360,它们引入了密封类型)并不是任何特定Java版本的目标。

尽管缺乏具体的路线图,但整个代数数据类型和模式匹配机制很有可能可以在下一个LTS版本(即2021年9月的Java 17)中以标准化的形式及时交付。

判决:正在进行中(作为Amber项目的一部分)

结构类型

自Java 8以来,Java的类型系统已经有了一定程度的发展,但是在实践中并没有朝着通用的结构类型的方向发展。例如,在设计记录时,为了使记录成为命名类型,显式地拒绝了结构类型。

这就强化了这样一个观念,即我们赋予类型的名称具有强大的力量和重要性,Java记录不仅仅是由其组件的数量和类型来定义的。

在Java中,类似于结构类型的东西仍然隐约可见的一个小地方是在Java的不可表示类型中。实际上,这些只是最初在2015年文章中讨论的示例的一个扩展。

在这个例子中,我们构造了一个看起来像结构类型的对象(Object + ),但只能在单个表达式中使用它,因为没有可表示的类型能够用作可赋值的变量类型。

从Java 10开始,该语言就已经具有类型推断的扩展形式了,类型推断使用var来减少赋值中的样板。我们能够使用此特性来http://extend the scope”>扩展作用域,在作用域内,我们可以调用以这种方式定义在类型上的其他方法。但是,这仅限于发生类型推断的方法。 var推断的特殊类型不能精确地跨越方法的边界,因为它是不可表示的。

实际上,这些特殊案例并不是真正的结构类型,也没有引入它的意图。 Java的设计对名称和命名类型的吸引力太强了。

判决:考虑过但驳回了

动态调用点

在过去的五年中,对invokedynamic的使用已经有了很大的扩展,尽管只是在JDK和少量技术成熟的外部库中。

正如原文所述,“Java语言没有关键字或其他结构来创建通用的invokedynamic调用点”。

关于可以扩展Dynalink库来承担这个角色的建议从未被采纳过,实际上,产生Dynalink的Nashorn Javascript实现本身现在也已经被弃用了,可以从Java 15中删除(尽管Dynalink本身将保留)。

那些真正使用动态调用点的库通过MethodHandles API来实现的,尽管该方法在2020年使用起来会稍微容易一些,但是对大多数Java程序员来说,它仍然是遥不可及的。

在不引发太多运行时问题的灵活动态调用和引人注目的语言级别使用之间,寻求平衡的困难已经被证明了,该困难至少在目前是非常巨大的。

判决:尚不予考虑

我错过了什么?

在过去的5年里,也出现了一些项目和趋势,这些项目和趋势我并没有在最初的文章中预测或解决。其中最重要的可能是:

  • Valhalla项目的程度和范围
  • Amber项目
  • Java最新的发布模型
  • Graal和GraalVM
  • Kotlin的崛起

举几个例子:

尽管Valhalla项目是于2014年启动的,但在随后的几年里,它势头强劲并取得了巨大的发展。它已经成为Java迄今为止最雄心勃勃、最大的变化了。 Valhalla承诺将会修改Java平台的各个方面:从内存和值在VM中的表示方式,到类型系统和泛型,再到库级和语言级语法。

该项目旨在使Java与当前和未来的硬件状态保持一致,并提供性能和其他一些根本无法单独解决的改进。相反,Valhalla的目标是将Java平台的状态从当前位置(我们可以认为是局部最大值)转移到一个更适合作为未来几十年平台基础的位置。

最初的研究总是很难预测的,因此Graal的兴起也让我感到惊讶,但也不足为奇。与其他许多引人入胜的概念一样,一旦你掌握了它,它的基本概念就会变得非常简单。

Java常用的JIT编译器是用C++代码编写的,并在JVM特殊的专用线程上执行。 Graal从一个简单的想法开始:如果JIT编译器是用Java编写的,而实际上编译器线程正在运行的是Java解释器的第二个副本,那该怎么办?

解释模式的JIT编译器将具有与当前JIT相同的特性。因此它可以将任何类文件编译为机器码。我们应该预期它会比现有的C++编译器慢,但它的行为并不会有所不同,只是在性能上不同。

将此想法归结为逻辑结论,这意味着解释模式JIT可以编译构成JIT本身的类文件。一旦预热,它就可以替换自己,并以与原始的原生JIT相同的性能运行。

事实证明,这个引人入胜的想法是一大类新技术的起点,其中包括Java的本地编译(AOT)以及能够运行多种不同语言的全新的多语言虚拟机(GraalVM)。

结论

在过去的五年中,Java平台已经变得越来越复杂了,有许多新的语言和虚拟机(VM)特性已经交付或正在开发。假设按照当前的趋势继续下去,社区最感兴趣的可能是在Java 17(将于2021年9月发布)中提供的一组标准化的特性。

这将是一个截然不同的Java, 与我们在2014年最初观察时的Java不同,虽然某些特性已经交付了,但似乎很明显,其他一些特性不太可能实现了,还有一些特性是通过完全不同的形式实现的。我们期待着看到未来五年Java语言和平台的发展,尤其是那些我们目前尚无法预测的方面。

作者介绍

Ben Evans 是JVM性能优化公司jClarity的联合创始人。他是LJC(伦敦的JUG)的组织者和 JCP执行委员会成员,帮助定义Java生态系统的标准。Ben是Java冠军、3次 JavaOne Rockstar 发言人;他是《全能Java开发人员》和《Java简介》、《优化Java》新版的作者。他定期为 Java平台、性能、架构、并发性、创业企业等相关主题发表演说。Ben有时可以提供演讲、教学、写作和咨询服务——请联系他获取详细信息。

原文链接:

Java’s Missing Features: Five Years Later