一文搞定 Java 10 新特性

大家好,我是大明哥,一个专注「死磕 Java」系列文章创作的一线程序员。 本文已收录到我的小站:skjava.com


Java 10 是Java历史上的一个较小的版本,发布于2018年3月。

JEP 286:局部变量类型推断

Java 10中引入了var关键字,允许开发者在声明局部变量时不必显式声明变量的类型,编译器会自动根据变量的初始值推断变量的类型。这使得代码更加简洁,尤其是在处理泛型时。例如:

ini 复制代码
var list = new ArrayList<String>();  // 编译器推断 list 是 ArrayList<String> 类型
var stream = list.stream();          // 编译器推断 stream 是 Stream<String> 类型

**需要注意的是,****var**只能用在局部变量上,不能用于类的成员变量、方法参数或返回类型。

详情请参考:Java 10 新特性---局部变量类型推断

JEP 304:统一的垃圾回收接口

在当前的 Java 结构中,组成垃圾回收器(GC)实现的组件分散在代码库的各个部分。尽管这些惯例对于使用 GC 计划的 JDK 开发者来说比较熟悉,但对新的开发人员来说,对于在哪里查找特定 GC 的源代码,或者实现一个新的垃圾收集器常常会感到困惑。更重要的是,随着 Java modules 的出现,我们希望在构建过程中排除不需要的 GC,但是当前 GC 接口的横向结构会给排除、定位问题带来困难。

为解决此问题,需要整合并清理 GC 接口,以便更容易地实现新的 GC,并更好地维护现有的 GC。Java 10 中,hotspot/gc 代码实现方面,引入一个干净的 GC 接口,改进不同 GC 源代码的隔离性,多个 GC 之间共享的实现细节代码应该存在于辅助类中。这种方式提供了足够的灵活性来实现全新 GC 接口,同时允许以混合搭配方式重复使用现有代码,并且能够保持代码更加干净、整洁,便于排查收集器问题。

JEP 307:并行全垃圾回收器 G1

从 Java9 开始 G1 就了默认的垃圾回收器,G1 是以一种低延时的垃圾回收器来设计的,旨在避免进行 Full GC,但是 Java9 的 G1 的 FullGC 依然是使用单线程去完成标记清除算法,这可能会导致垃圾回收期在无法回收内存的时候触发 Full GC。

为了最大限度地减少 Full GC 造成的应用停顿的影响,Java 10 为 G1 引入多线程并行 GC,同时会使用与年轻代回收和混合回收相同的并行工作线程数量,从而减少了 Full GC 的发生,以带来更好的性能提升、更大的吞吐量。

为了利用并行 Full GC,通常不需要特别的配置,因为 G1 在 Java 10 及以上版本默认就是并行执行 Full GC 的。但是,可以通过 JVM 参数来调整并行线程的数量, -XX:ParallelGCThreads=<N> 参数,其中 <N> 是希望使用的线程数。

JEP 310:应用程序类数据共享

应用程序类数据共享(Application Class-Data Sharing, 简称 AppCDS),旨在减少应用程序的启动时间,并减少Java应用程序在运行时的内存占用。

AppCDS 是在 Java 5 中引入的类数据共享(Class-Data Sharing, CDS)的一个扩展。CDS 的主要目的是通过共享已知库(比如 Java 核心库)的元数据,来加快 JVM 的启动时间和减少内存占用。在 Java 9 之前,CDS 仅限于 JDK 内置的类加载器和 Java 核心类。而从 Java 10 开始,AppCDS 允许开发者将应用程序自己的类包含进共享归档中,从而提升了启动性能和减少了资源占用。其工作原理如下:

  1. 静态归档 : 在第一次执行时,JVM 会进行一个标准的类加载过程。在这个过程中,JVM 会解析所有的类和生成相应的元数据。使用 AppCDS 时,可以通过 -Xshare:dump 选项指示 JVM 保存这些元数据到一个静态归档文件中(通常是一个 .jsa 文件)。
  2. 共享使用 : 在接下来的启动过程中,可以通过 -Xshare:on-XX:SharedArchiveFile=path_to_jsa_file 选项来指示 JVM 使用先前创建的归档文件。这样,JVM 可以快速地映射归档文件中的数据到内存中,而不是重新解析所有类。
  3. 动态归档: Java 10 引入了动态类数据共享,即在应用程序运行时动态生成共享归档,这允许共享更多的类和加载器类型。

JEP 312:线程-局部变量管控

这是在 JVM 内部相当低级别的更改,现在将允许在不运行全局虚拟机安全点的情况下实现线程回调。这将使得停止单个线程变得可能和便宜,而不是只能启用或停止所有线程。

JEP 313:移除 Native-Header 自动生成工具

在 Java 9 之前,javah 是一个用来生成 C 头文件(即 .h 文件)的工具,这些头文件是从 Java 代码中定义的 native 方法所必需的,通常用于 Java 与本地代码(如 C 或 C++ 代码)之间的互操作。

但是它在 Java 9 被废弃,并在 Java 10 中被移除,原因是 javac 编译器已经提供了相同的功能。从 Java 8 开始,javac 编译器引入了 -h 选项,使得开发者可以在编译 Java 源代码的同时生成对应的本地方法头文件。因此,保留 javah 就显得多余,也使得工具链更加简化。

JEP 314:额外的 Unicode 语言标签扩展

该扩展主要是为了提升了java.util.Locale 类的能力,使得它能够更好地支持 BCP 47 语言标签以及 Unicode 扩展。

BCP 47 是"Best Current Practice 47"的缩写,它定义了一套用于标识人类语言的标签系统。这个标准不仅包括了 ISO 语言代码,还包括了扩展语言子标签、脚本、区域以及变体等。在 Java 7 中引入了对 BCP 47 语言标签的基本支持,但对扩展的支持并不完整。

Unicode 扩展是一系列的代码,用来标识与特定区域设置相关联的特定行为,例如,日历类型、数字系统等。在此次升级中增加了如下扩展支持:

编码 注释
cu 货币类型
fw 一周的第一天
rg 区域覆盖
tz 时区

Java 10 提升了对这些 Unicode 扩展的支持,特别是与区域设置相关的功能。这项增强允许开发者在 Java 应用程序中指定更详细的语言和区域设置偏好。

JEP 316:备用存储装置上的堆分配

传统上,Java 的堆内存(heap memory)是在主内存(RAM)中分配的。随着新型内存技术的出现,特别是非易失性内存(Non-Volatile Memory, NVM),出现了新的使用可能性。

Java 10 新特性(备用存储装置上的堆分配)允许 JVM 能够使用适用于不同类型的存储机制的堆,在可选内存设备上进行堆内存分配。这么做的目的是为了允许使用那些具有不同性能特征存储设备的系统上的 JVM 更好地管理其内存。

**注:**NVM 是一种保持存储信息即使在没有电力的情况下也不会丢失数据的内存类型,这对于数据的持久性和快速访问有很大的优势。

使用参数 -XX:+UseNVDIMM 来开启。

需要注意的是该项特性是一个实验性特性,意味着在未来的 Java 版本中可能会有变更,且需要相应的硬件设备和操作系统需要支持 NVM。

JEP 317:基于 Java 的 实验性 JIT 编译器

Java 10 引入了一项名为 "基于 Java 的实验性 JIT 编译器" 的新特性,该编译器是基于 Graal 开源项目,用 Java 编写的。Java 10 将其用作 Linux/x64 平台上的实验性 JIT 编译器开始进行测试和调试工作,以作为 Java HotSpot VM 的一个实验性替代品。

由于 Graal 是一个相对较新的项目,并且 JIT 编译器对于 JVM 的性能至关重要,因此 Graal JIT 被标记为实验性特性。这意味着它不是默认激活的,并且在未来的版本中可能会有较大的改变。开启方式如下:

diff 复制代码
-XX:+ UnlockExperimentalVMOptions -XX:+ UseJVMCICompiler

JEP 319:根证书认证

在 Java 应用中,安全的网络通信经常依赖于 SSL/TLS 协议。这些协议使用证书来实现服务器的身份验证,以保护用户免受中间人攻击。证书通常由证书颁发机构(CAs)签发。为了验证一个给定的证书,Java 运行时需要访问可信的 CA 根证书。如果没有这些根证书,Java 应用可能无法与使用 SSL/TLS 的服务通信,或者需要额外的配置才能工作。

然而,自 Java 9 起在 keytool 中加入参数 -cacerts ,可以查看当前 JDK 管理的根证书,但是 Java 9 中 cacerts 目录为空,需要手动安装和管理根证书,这样会给开发者带来很多不便。所以从 Java 10 开始,将会在 JDK 中提供一套默认的 CA 根证书。该跟证书是 OpenJDK 提供的一组开源的 CA 根证书,这样就不再需要手动配置 CA 根证书,因为它们已经包含在 JDK 中了。

JEP 322:基于时间的版本发布模式

以前 Java 的更新和新版本发布没有固定的时间表。新的特性是在它们完成后发布,这就会导致 Java 长时间没有更新,或者更新之间的时间间隔不确定。这种模式对于希望规划未来功能和改进的开发者和企业来说是个挑战。

所以 Java 10 引入了一种新的版本发布模式,标志着 Oracle 对 Java 发布策略的一次重大改变。这一新模式被称为基于时间的发布版本模式,这就意味着 Java 将会有更加频繁且可预测的版本更新。

在基于时间的版本发布模式下,Java 版本将在每个季度(1 月,4 月,7 月,10 月)发布。 更新版本将严格限于安全性问题,回归和较新特性中的错误的修复。 按照进度计划,可以说每个特性版本在下一个特性版本发布之前都会收到两个更新。

新的版本好格式如下:

bash 复制代码
$FEATURE.$INTERIM.$UPDATE.$PATCH
名称 描述
$FEATURE 它会每 6 个月增加一次,具体取决于特性发布版本,例如:JDK 10,JDK11。(以前为$MAJOR。)
$INTERIM 通常为零,因为六个月内不会有任何中期发布。 对于包含兼容的错误修复和增强特性但不兼容的更改,不删除的特性以及对标准 API 的更改的非特性版本,它将增加。 (以前为$MINOR。)
$UPDATE 对于解决安全问题,回归和较新特性中的错误的兼容更新版本,它将递增。 (以前为$SECURITY。)
$PATCH 仅在需要紧急发布以解决关键问题时才会增加。

新增 API

Java 10 中添加了 73 个新 API,下面是一些最主要的:

API 描述
List.copyOf, Set.copyOf, Map.copyOf 这些方法提供了一种创建不可修改集合的快捷方式,参数是现有的集合。
Collectors.toUnmodifiableList, Collectors.toUnmodifiableSet, Collectors.toUnmodifiableMap 这些方法允许将Stream的元素收集到不可修改的集合中
Optional.orElseThrow() Optional.get()的一个更易读的替代,它在值不存在时抛出NoSuchElementException

关于 copyOf() 更多信息参考文章:Java 10 新特性---不可变集合的增强

相关推荐
追风林几秒前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨15 分钟前
El表达式和JSTL
java·el
许野平41 分钟前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
duration~1 小时前
Maven随笔
java·maven
zmgst1 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD1 小时前
前后端分离,Jackson,Long精度丢失
java
blammmp1 小时前
Java:数据结构-枚举
java·开发语言·数据结构
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong2 小时前
Java反射
java·开发语言·反射
齐 飞2 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb