五年过去了,再看 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)的角色:

1var 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 语言和平台的发展,尤为是那些咱们目前尚没法预测的方面。

相关文章
相关标签/搜索