Java 10是其23年历史中发布速度最快的Java版本。Java一直因其增长缓慢和演进速度慢而受到批评,但Java 10打破了这一观念。Java 10是一个具有许多未来变化的版本,其范围和影响可能并不明显,但却是深远的。在这篇文章中,我们将讨论Java 10版本中引入的各种功能。在此之前,让我们回顾一下引入Java版本模型的一些变化。
长期支持模型
自2017年起,Oracle和Java社区宣布将Java切换到新的6个月发布周期。它转向了Oracle Java SE产品的长期支持(LTS)模型。这意味着什么?产品的LTS版本将获得来自Oracle的首要和持续支持,每3年进行一次定向。每个Java版本都以一个或两个主要功能为模型,这些功能推动了发布。任何障碍都会推迟发布并使其上市时间延迟。Java 9的一个主要功能是项目Jigsaw,它多次推迟了发布日期,发布延迟了1.5年以上。6个月的发布周期将遵循一个发布列车。发布列车将每6个月制定一次计划。符合要求的功能将被列入列车;否则,它们将等待下一次计划的列车。
Oracle JDK vs Open JDK
为了更加友好于开发者,Oracle和Java社区现在将OpenJDK二进制文件作为未来主要的JDK推广。这是对早期情况的一大解脱,早期的JDK二进制文件是专有的,并由Oracle许可,其在再分发方面有各种限制。然而,Oracle将继续生产他们的JDK,但仅用于长期支持版本。这是朝着更加云端友好和容器友好的方向迈出的一步,因为OpenJDK二进制文件可以作为容器的一部分进行分发。这意味着什么? OpenJDK二进制文件将每6个月发布一次,而Oracle JDK二进制文件将每3年发布一次(LTS版本)。哪个JDK二进制文件会被采用? 大型组织需要时间来在各个版本之间进行迁移;他们会坚持某个版本直到可以。Java 6的行业采用率高于Java 7,然后行业逐渐向Java 8过渡。在我看来,LTS版本将是企业最青睐的版本之一。然而,它是否会是Oracle JDK的LTS版本还是Open JDK的LTS版本尚未可知,部分原因是云端空间发展迅猛。Java 9和10是非LTS版本。预计将于2018年9月发布的Java 11将是一个LTS版本。
Java 10功能
让我们来一睹Java 10中可用的功能。
随着时间为基础的发布周期的采用,Oracle 改变了 Java SE 平台和 JDK 的版本字符串方案,以及与当前和未来时间为基础的发布模型相关的版本信息。版本号的新模式是:$FEATURE.$INTERIM.$UPDATE.$PATCH
。$FEATURE:计数器将每6个月递增一次,并基于功能发布版本,例如:JDK 10、JDK 11。$INTERIM:计数器将用于不包含不兼容更改的兼容性 bug 修复和增强功能的非功能性发布。通常情况下,这将为零,因为在六个月的时间内不会有中间发布。这将保留用于发布模型的未来修订。$UPDATE:计数器将用于修复安全问题、回归和新功能中的错误的兼容性更新发布。此版本将在功能发布后一个月更新,然后每3个月更新一次。2018年4月发布的是 JDK 10.0.1,7月发布的是 JDK 10.0.2,依此类推。$PATCH:计数器将用于紧急发布以修复关键问题。已添加新的 API 以便以编程方式获取这些计数器值。让我们来看一下;
Version version = Runtime.version();
version.feature();
version.interim();
version.update();
version.patch();
现在,让我们来看一下返回版本信息的 Java 启动器:
$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
版本号格式为“10”,因为除了零以外没有其他计数器。发布日期被添加了进去。18.3 可以被解读为 2018 年的第3个月,构建 10+46 是版本 10 的第46次构建。对于 JDK 10.0.1 的假设构建 93,构建将为 10.0.1+939。### 本地变量类型推断(JEP 286)
本地变量类型推断是Java 10中开发者最重要的新功能。它在具有初始化程序的本地变量的声明中添加了类型推断。局部类型推断仅适用于以下场景:
- 仅限具有初始化程序的本地变量
- 强化for循环或索引
- 在for循环中声明的本地变量
让我们看看它的用法:
var numbers = List.of(1, 2, 3, 4, 5); // inferred value ArrayList
// 强化for循环的索引
for (var number : numbers) {
System.out.println(number);
}
// 在循环中声明的本地变量
for (var i = 0; i < numbers.size(); i++) {
System.out.println(numbers.get(i));
}
您可以在我们的专题文章中了解更多关于Java 10本地变量类型推断的信息。13. ### 实验性的基于Java的JIT编译器(JEP 317)
此功能使得基于 Java 的 JIT 编译器 Graal 能够在 Linux/x64 平台上作为实验性 JIT 编译器使用。这是 Java 10 功能列表中迄今为止最具未来感的一个。Graal 是在 Java 9 中引入的。它是 JIT 编译器的另一种选择,与我们以往所使用的 JIT 编译器不同。它是 JVM 的一个插件,这意味着 JIT 编译器与 JVM 没有耦合,可以动态地插入和替换为符合 JVMCI(Java-Level JVM Compiler Interface)标准的任何其他插件。它还为 Java 世界带来了 Ahead of Time (AOT) 编译。它还支持多语言解释。”一个基于 Java 的即时编译器,用 Java 编写的,用于将 Java 字节码转换为机器码。”这样说是否让人感到困惑?如果 JVM 是用 Java 编写的,那么你难道不需要一个 JVM 来运行 JVM 吗?JVM 可以被 AOT 编译,然后 JIT 编译器可以在其中使用以通过实时代码优化提高性能。Graal 是 Java 中 JIT 编译器的完全重写。以前的 JIT 编译器是用 C++ 编写的。它被认为是任何编程语言的最后一个演化阶段之一。您可以通过以下 JVM 参数切换到 Graal:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
您可以从Chris Seaton 的演示中了解更多关于 Graal 的信息。
此功能有助于改善启动时的内存占用,将现有的类数据共享(“CDS”)功能扩展到允许将应用程序类放置在共享存档中。 JVM 在启动时执行一些预备步骤,其中之一是将类加载到内存中。如果有多个 JAR 文件包含多个类,则首次请求的延迟会明显可见。这在无服务器架构中成为一个问题,其中启动时间至关重要。为了缩短应用程序启动时间,可以使用应用程序类数据共享。其思想是通过在不同的 Java 进程之间共享通用类元数据来减少内存占用。可以通过以下 3 个步骤实现:确定要存档的类:使用 Java 启动器创建要存档文件的列表,可以通过以下参数实现:
$java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld
创建 AppCDS 存档:使用 Java 启动器创建用于应用程序 CDS 的存档文件列表,可以通过以下参数实现:
$java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa -cp hello.jar
使用 AppCDS 存档:使用以下参数的 Java 启动器来使用应用程序 CDS。
$java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloWorld
G1 垃圾收集器已成为JDK 9的默认选项。G1垃圾收集器避免了任何完全的垃圾收集,但是当用于收集的并发线程无法及时恢复内存时,用户的体验会受到影响。此更改通过将完全GC并行化来改进G1的最坏情况延迟。G1收集器的标记-清除-整理算法作为此更改的一部分被并行化,并且当用于收集的并发线程无法及时恢复内存时将被触发。25. ### 垃圾收集器接口(JEP 304)
这个JEP是一项前瞻性的更改。通过引入通用的垃圾收集器接口,它提高了不同垃圾收集器的代码隔离性。此更改为内部GC代码提供了更好的模块化。它将有助于在未来添加新的GC而无需更改现有的代码库,同时有助于删除或清理以前的GC。26. ### 附加Unicode语言标签扩展(JEP 314)
此功能增强了java.util.Locale和相关API,以实现BCP 47语言标签的附加Unicode扩展。截至Java SE 9,支持的BCP 47 U语言标签扩展为“ca”和“nu”。此JEP将支持以下附加扩展:
- cu(货币类型)
- fw(一周的第一天)
- rg(区域覆盖)
- 系统: 时区(time zone)
为了支持这些附加扩展,对各种 API 进行了更改,以提供基于 U 或其他附加扩展的信息。
java.text.DateFormat::get*Instance
java.text.DateFormatSymbols::getInstance
java.text.DecimalFormatSymbols::getInstance
java.text.NumberFormat::get*Instance
java.time.format.DateTimeFormatter::localizedBy
java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern
java.time.format.DecimalStyle::of
java.time.temporal.WeekFields::of
java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}
java.util.Currency::getInstance
java.util.Locale::getDisplayName
java.util.spi.LocaleNameProvider
为了推广 OpenJDK 并使其更受社区用户欢迎,此功能在 JDK 中提供了一组默认的根证书颁发机构(CA)证书。这也意味着 Oracle 和 Open JDK 二进制文件在功能上将是相同的。诸如 TLS 等关键安全组件将在未来的 OpenJDK 构建中默认运行。30. ### 线程本地握手(JEP 312)
这是一项用于提高性能的内部 JVM 功能。握手操作是在每个 JavaThread 处于安全点状态时执行的回调。该回调由线程本身执行,或者由 VM 线程执行,同时保持线程处于阻塞状态。此功能提供了一种在不执行全局 VM 安全点的情况下在线程上执行回调的方法。使得可以轻松地停止单个线程,而不仅仅是所有线程或无线程。31. ### 在替代性存储设备上进行堆分配(JEP 316)
应用程序变得越来越占用内存,云原生应用程序、内存数据库和流应用程序的增加。为了满足这些服务,提供了各种内存架构。这个功能增强了HotSpot VM的能力,可以将Java对象堆分配到用户指定的替代内存设备上,比如NV-DIMM。该JEP针对具有与DRAM相同语义的替代内存设备,包括原子操作的语义,因此可以在不改变现有应用程序代码的情况下,将其用于对象堆而不是DRAM。32. ### 移除本地头生成工具 – javah (JEP 313)
这是一项管理性的变更,将javah工具从JDK中移除。该工具功能已经在JDK 8的javac
中添加,它提供了在编译时编写本地头文件的能力,使得javah
变得无用。35. ### 将JDK Forest合并为单一存储库 (JEP 296)
多年来,JDK代码库中存在着各种Mercurial存储库。不同的存储库确实提供了一些优势,但也存在各种运营上的缺陷。作为这一变更的一部分,将JDK Forest的多个存储库合并为一个单一的存储库,以简化和优化开发流程。36. ### API更改
Java 10添加了一些API并移除了一些API(是的,这不是打错字)。Java 9引入了增强的过时功能,其中某些API被标记为将在将来的版本中删除。已删除的API:您可以在这里找到已删除的API。已添加的API:Java 10中添加了73个新API。您可以在这里找到已添加的API以及进行比较。让我们来看一下其中的一些新增内容:
- 添加了List、Map和Set接口,并带有静态的copyOf(Collection)方法。它返回一个包含提供的条目的不可修改的List、Map或Set。对于List,如果后续修改了给定的List,返回的List将不会反映这些修改。
- Optional及其基本变体获得了一个方法orElseThrow()。这与get()完全相同,但Java文档指出它是get()的首选替代方法。
- Collectors类获得了用于收集不可修改集合(Set、List、Map)的各种方法。
List actors = new ArrayList<>();
actors.add("Jack Nicholson");
actors.add("Marlon Brando");
System.out.println(actors); // prints [Jack Nicholson, Marlon Brando]
// 新增API - 从List创建一个不可修改的List。
List copyOfActors = List.copyOf(actors);
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
// copyOfActors.add("Robert De Niro"); 将生成一个
// UnsupportedOperationException
actors.add("Robert De Niro");
System.out.println(actors);// prints [Jack Nicholson, Marlon Brando, Robert De Niro]
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
String str = "";
Optional name = Optional.ofNullable(str);
// 新增API - 是get()方法的首选选项
name.orElseThrow(); // same as name.get()
// 新增API - Collectors.toUnmodifiableList
List collect = actors.stream().collect(Collectors.toUnmodifiableList());
// collect.add("Tom Hanks"); // 将生成一个
// UnsupportedOperationException
结论
在本文中,我们介绍了Java 10的不同新功能。如果您认为有任何重要内容被忽略了,请通过评论告诉我们。通常您可以在GitHub 这里查看完整的代码。
Source:
https://www.digitalocean.com/community/tutorials/java-10-features