JDK 10 新特性详解

JDK 10 新特性详解

发布日期 :2018 年 3 月 20 日

规范版本 :Java SE 10(JSR 383)

是否 LTS :否

主题 :局部变量类型推断 var ------ 时间驱动版本模型的第一个正式版本


一、版本总览

JDK 10 是 Java 转向 6 个月一个特性版本 后的第一个正式发布版本(相关机制由 JEP 322 确立)。特性数量不多,但 var 是自 Java 8 以来最受欢迎的语言特性之一。

JDK 10 共集成 12 个 JEP。


二、核心特性

1. JEP 286:局部变量类型推断(var)

目标:减少编写 Java 代码时的样板化,同时保持 Java 的静态类型安全性。

java 复制代码
// 之前
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> list = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

// JDK 10
var map = new HashMap<String, List<String>>();
var list = new ArrayList<String>();
var reader = new BufferedReader(new InputStreamReader(System.in));

语义 :var 不是「动态类型」,而是编译期由初始化器推断出的静态类型。编译后字节码与显式声明完全等价。

java 复制代码
var x = 10;              // x 的类型是 int(不是 Object 或 Integer)
x = "hello";             // 编译错误:不兼容的类型

适用位置:

java 复制代码
// ✅ 带初始化器的局部变量
var name = "Alice";

// ✅ for 循环初始化器
for (var i = 0; i < 10; i++) { }

// ✅ 增强 for 循环变量
for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + "=" + entry.getValue());
}

// ✅ try-with-resources
try (var in = new FileInputStream("a.txt")) { }

不适用位置(编译错误):

  • 方法参数、方法返回值类型
  • 字段(成员变量)
  • 没有初始化器的局部变量:var x;
  • 初始化为 null:var x = null;
  • 数组初始化器的简写:var arr = {1, 2, 3};(需写 new int[]{1,2,3})
  • lambda 参数(JDK 11 的 JEP 323 才支持)
  • 复合声明:var a = 1, b = 2;

命名约定 :var 是保留类型名(reserved type name),不是关键字。因此仍可用作变量名、方法名、包名,但不能用作类名或接口名。

java 复制代码
var var = 10;   // 合法,但不推荐
class var {}    // 编译错误

最佳实践:

  • 在类型很明显时使用 var(右侧有构造函数或工厂方法)
  • 在类型不明显时避免使用(如 var result = compute();------看不出返回类型)
  • 变量名要能传达语义

2. JEP 304:垃圾收集器接口(Garbage-Collector Interface)

重构 HotSpot 内部 GC 代码,引入统一的 CollectedHeap 抽象,让新增 GC 实现更简单。这是 Shenandoah、ZGC 等后续 GC 能快速集成的基础设施改进。

对应用无直接影响,但为后续 GC 引入铺平了道路。

3. JEP 307:G1 的并行 Full GC

问题 :JDK 9 中 G1 的 Full GC 是单线程的,在堆大、Full GC 频繁的场景下性能很差。

改进 :Full GC 改为并行执行,使用与 Young/Mixed GC 相同的并行 worker 线程。

bash 复制代码
# 控制并行 Full GC 的线程数
java -XX:ParallelGCThreads=8 MyApp

收益:Full GC 停顿时间显著下降(在典型场景下可减少数倍)。

4. JEP 310:应用程序类数据共享(AppCDS)

背景 :JDK 5 引入 CDS(Class Data Sharing),但只能共享 JDK 的核心类。AppCDS 允许把应用程序自己的类也加入共享归档。

工作流程:

bash 复制代码
# 步骤 1:创建类列表(第一次试运行)
java -Xshare:off -XX:DumpLoadedClassList=app.lst -cp app.jar com.example.Main

# 步骤 2:基于列表生成归档
java -Xshare:dump -XX:SharedClassListFile=app.lst \
     -XX:SharedArchiveFile=app.jsa -cp app.jar

# 步骤 3:使用归档启动
java -XX:SharedArchiveFile=app.jsa -cp app.jar com.example.Main

收益:

  • 启动时间减少 20%~40%(视应用规模)
  • 内存占用降低(共享归档映射到多个 JVM 进程,物理内存只占一份)

与 JDK 12/JEP 341(默认 CDS 归档)、JDK 13/JEP 350(动态 CDS)的关系:

  • JDK 12 提供了 默认 CDS 归档(JDK 自带)
  • JDK 13 引入动态归档 ,可在应用退出时自动生成 app.jsa,无需两次手动运行

5. JEP 312:线程局部握手(Thread-Local Handshakes)

背景 :JVM 执行某些操作(如 -XX:+PrintFlagsFinal、去优化、偏向锁撤销)需要对所有线程执行安全点(safepoint)操作,这会导致全局停顿。

改进 :允许只对单个线程执行握手操作,无需全局 safepoint。

bash 复制代码
# 使用线程局部握手来减少全局 safepoint
java -XX:+UseThreadLocalHandshakes MyApp   # JDK 10 中默认开启

收益:

  • 减少全局 safepoint 停顿
  • 为后续低延迟特性(如 JEP 312 减化偏向锁撤销、Project Loom)奠定基础

在后续版本中,该功能成为默认且不可关闭。

6. JEP 313:移除 javah 工具

javah 用于从 Java 类生成 JNI 头文件。JDK 10 中移除,功能由 javac -h 提供:

bash 复制代码
# 旧方式
javah -d headers com.example.MyClass

# 新方式(JDK 8 起支持)
javac -h headers com/example/MyClass.java

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

在 java.util.Locale 和 java.text.* 中支持更多 BCP 47 语言标签扩展。

新增支持的扩展键:

  • ca(日历)
  • co(排序规则)
  • cu(货币)
  • fw(一周的第一天)
  • rg(区域覆盖)
  • tz(时区)
  • nu(数字系统)
java 复制代码
// 使用 u-ca 指定公历
Locale locale = Locale.forLanguageTag("en-US-u-ca-buddhist");
// 使用 nu 指定数字系统
Locale arabicNumeric = Locale.forLanguageTag("ar-EG-u-nu-latn");

8. JEP 316:在替代内存设备上分配堆内存

允许 JVM 堆使用 NV-DIMM 等替代内存设备,通过 -XX:AllocateHeapAt 指定路径:

bash 复制代码
java -XX:AllocateHeapAt=/mnt/nvram MyApp

收益:利用非易失性内存的低延迟、大容量特性。

9. JEP 317:实验性基于 Java 的 JIT 编译器(Graal)

允许把 Graal 作为 JIT 编译器使用:

bash 复制代码
java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler MyApp

参数说明:

  • 需要 JVMCI(JEP 243)支持,JDK 10 已内置
  • -XX:+EnableJVMCI 默认开启

注意 :这是一个实验性且未完成的特性。JDK 16 中被移除(JEP 410),Graal 转移到 GraalVM 项目独立发展。

10. JEP 319:根证书(Root Certificates)

问题 :JDK 之前不自带受信任的根 CA 证书,cacerts 密钥库是空的,导致 HTTPS 请求需要手动导入证书。

改进 :JDK 10 的 cacerts 密钥库预置了 Oracle 认可的 CA 根证书集合,开箱即可访问主流 HTTPS 站点。

java 复制代码
// JDK 10 起可直接工作
var client = HttpClient.newHttpClient();
var resp = client.send(
    HttpRequest.newBuilder(URI.create("https://example.com")).GET().build(),
    HttpResponse.BodyHandlers.ofString());

11. JEP 322:基于时间的版本发布模型

这是 JDK 10 最具战略意义的变更,它定义了此后所有 JDK 版本的编号与发布规则。

新版本号格式:

text 复制代码
$FEATURE.$INTERIM.$UPDATE.$PATCH

例:11.0.4、17.0.1、21.0.3
组件 含义 示例
$FEATURE 特性版本号,每 6 个月递增 1 17
$INTERIM 中间版本号,通常为 0(保留) 0
$UPDATE 更新版本号,每季度递增 1(安全与 bug 修复) 4
$PATCH 紧急补丁版本号,非常规发布时为 0 0

java -version 输出:

text 复制代码
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment 18.9 (build 11.0.4+11)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.4+11, mixed mode)

发布节奏:

类型 频率 时间点
特性版本 每 6 个月 每年 3 月和 9 月
更新版本 每 3 个月 每年 1、4、7、10 月
LTS 每 2 年(后改为每 2 年,再改为每 2 年,具体见下文) 11、17、21、25...

LTS(长期支持)版本:Oracle 大约每 2 年指定一个 LTS 版本。LTS 版本获得更长时间的修复支持,适合生产环境。

相关版本号 API:

java 复制代码
Runtime.Version version = Runtime.version();
System.out.println(version.feature());    // 11
System.out.println(version.interim());    // 0
System.out.println(version.update());     // 4
System.out.println(version.patch());      // 0
System.out.println(version);              // 11.0.4+11

Runtime.Version 类在 JDK 9 中以 java.lang.Runtime.Version 引入;JDK 10 细化了 version() 方法语义。


三、JDK 10 的移除与弃用

JEP 内容
313 移除 javah 工具

其它变化(非 JEP):

  • java.security.acl 包被弃用
  • 若干 sun.* 内部 API 继续被封装
  • javax.management 的部分实现被清理

四、JDK 10 特性速查表

类别 JEP 特性
语言 286 局部变量类型推断 var
库 314 Unicode 语言标签扩展
库 319 根证书(cacerts 预置)
VM 304 垃圾收集器接口
VM 307 G1 并行 Full GC
VM 312 线程局部握手
VM 316 替代内存设备上的堆分配
VM 317 实验性 Graal JIT(JVMCI)
工具 310 AppCDS(应用程序类数据共享)
工具 313 移除 javah
流程 322 基于时间的版本发布模型
流程 296 将 JDK 森林合并为单一仓库

五、升级注意事项

  1. var 不会被「反编译」:字节码中类型仍是具体的,无需担心兼容性
  2. Graal JIT 是实验性的 :不要在生产环境使用 -XX:+UseJVMCICompiler
  3. AppCDS 归档与 JDK 版本绑定 :升级 JDK 后需重新生成 app.jsa
  4. javah 移除 :构建脚本需改为 javac -h
  5. 新版本号格式 :任何解析 java -version 输出或 java.class.version 的脚本需适配
  6. -XX:+UseThreadLocalHandshakes 在 JDK 10 中已默认开启,无需显式指定

六、参考资源


← JDK 9 | 返回索引 | JDK 11 →

相关推荐
xuxigifxfh6 小时前
HJ11 数字颠倒
java·开发语言·华为机考
wno7046 小时前
Spring Boot整合Quartz
java·spring boot·后端
一只旭宝6 小时前
数据结构与算法复习手册:从写过,到讲清楚
开发语言·数据结构·c++·算法
百度一下吧6 小时前
断网后 WebView 加载单页面应用:页面跳转 JS 加载失败的处理方案
开发语言·javascript·ecmascript
步行cgn6 小时前
MySQL 报错:Access denied for user ‘root‘@‘localhost‘ 详解
java·数据库·spring
神仙别闹6 小时前
基于C语言开发的捕捉流星小游戏
c语言·开发语言
程序员Sunday7 小时前
Promise.all、allSettled、race、any 怎么选,失败后其他请求会怎样
开发语言·前端·javascript
一个有温度的技术博主7 小时前
深拷贝和浅拷贝:一次“搬家”事故
java·后端
daxiangxm7 小时前
GEO策略:让AI直接引用你的内容
开发语言·团队开发·运维开发·个人开发·数据库开发
程序员清风7 小时前
AI时代建议学点自己真正感兴趣的!
java·后端·面试