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 森林合并为单一仓库 |
五、升级注意事项
var不会被「反编译」:字节码中类型仍是具体的,无需担心兼容性- Graal JIT 是实验性的 :不要在生产环境使用
-XX:+UseJVMCICompiler - AppCDS 归档与 JDK 版本绑定 :升级 JDK 后需重新生成
app.jsa javah移除 :构建脚本需改为javac -h- 新版本号格式 :任何解析
java -version输出或java.class.version的脚本需适配 -XX:+UseThreadLocalHandshakes在 JDK 10 中已默认开启,无需显式指定
六、参考资源
- 官方发布页:https://openjdk.org/projects/jdk/10/
- JEP 322(版本模型):https://openjdk.org/jeps/322
- JEP 286(var):https://openjdk.org/jeps/286
- JEP 310(AppCDS):https://openjdk.org/jeps/310