JDK 11 作为继 JDK 8 之后的首个长期支持版本,带来了许多切实提升开发效率和运行时性能的新特性。
| 特性类别 | 核心特性 | 主要价值 |
|---|---|---|
| 语言与API | 局部变量类型推断 (var) 增强 |
允许在 Lambda 表达式中使用 var 并添加注解,提高一致性与灵活性 。 |
| 语言与API | 字符串增强 | 新增 isBlank(), lines(), strip(), repeat() 等方法,简化日常字符串操作 。 |
| 语言与API | HTTP Client API 标准化 | 将孵化期的 API 转为标准库,支持 HTTP/2 和 WebSocket,提供同步/异步调用方式 。 |
| 性能与GC | ZGC (低延迟垃圾收集器) | 实验性引入,目标暂停时间 < 10ms,适合大内存应用 。 |
| 性能与GC | Epsilon (无操作垃圾收集器) | 仅分配内存,不回收,用于性能测试和内存压力测试 。 |
| 工具与诊断 | Flight Recorder (飞行记录器) | 从商业功能变为开源,提供低开销的生产环境诊断能力 。 |
| 开发体验 | 单文件源代码程序运行 | 无需先编译 (javac),可直接通过 java 命令运行 .java 文件 。 |
💡 核心特性详解与代码示例
1. 局部变量类型推断 (var) 增强
JDK 11 允许在 Lambda 表达式的参数中使用 var,这主要不是为了简化代码(因为类型本身可省略),而是为了能够在参数上添加注解,增强代码的约束力和可读性 。
java
import java.util.List;
import javax.annotation.Nonnull;
public class VarLambdaExample {
public static void main(String[] args) {
List<String> names = List.of("Alice", "Bob", "Charlie");
// 传统方式,若要加注解必须显式声明类型
// names.forEach((@Nonnull String s) -> System.out.println(s));
// JDK 11:使用 var 并添加注解
names.forEach((@Nonnull var s) -> System.out.println(s));
}
}
2. 字符串增强
JDK 11 为 String 类新增了多个非常实用的方法,让字符串处理变得更方便 。
java
public class StringEnhancements {
public static void main(String[] args) {
String space = " ";
System.out.println(space.isBlank()); // true: 判断字符串是否仅为空白字符
String unicodeSpace = " \u2000 "; // 包含Unicode空白符
System.out.println("Trim: [" + unicodeSpace.trim() + "]"); // 可能无法完全去除
System.out.println("Strip: [" + unicodeSpace.strip() + "]"); // 可去除所有空白字符
String multiLine = "Hello\nWorld\nJava11";
multiLine.lines().forEach(System.out::println); // 按行分割为Stream并处理
String joy = "Joy!";
System.out.println(joy.repeat(3)); // 输出:Joy!Joy!Joy!
}
}
3. 标准化 HTTP Client API
新的 HttpClient 位于 java.net.http 包下,支持现代网络协议,并提供了同步和异步两种调用方式,替代了老旧的 HttpURLConnection 。
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 实例
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
// 2. 构建请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get"))
.GET()
.build();
// 3. 发送同步请求
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());
// 4. 发送异步请求
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join(); // 等待异步操作完成
}
}
4. 文件读写简化
Files 类新增的 readString() 和 writeString() 方法,让小型文本文件的读写变得异常简洁 。
java
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileReadWriteExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get("example.txt");
// 一行代码写入文件
Files.writeString(path, "Hello, JDK 11 File API!");
// 一行代码读取文件
String content = Files.readString(path);
System.out.println(content);
}
}
5. 集合工厂方法与增强
List, Set, Map 接口都提供了新的 of() 方法用于创建不可变集合,以及 copyOf() 方法用于创建副本 。Optional 类新增了 isEmpty() 方法,使判断空值的逻辑更直观 。
java
import java.util.*;
public class CollectionOptionalExample {
public static void main(String[] args) {
// 创建不可变集合
List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B");
Map<String, Integer> map = Map.of("Key1", 1, "Key2", 2);
// List.copyOf 创建集合的不可变副本
List<String> copy = List.copyOf(list);
// Optional 的 isEmpty 方法
Optional<String> emptyOpt = Optional.empty();
System.out.println(emptyOpt.isEmpty()); // true
}
}
⚙️ 垃圾收集器与运行环境
1. 低延迟垃圾收集器 ZGC
ZGC 的设计目标是实现超低停顿时间(通常低于 10 毫秒),即使处理 TB 级别的堆内存也是如此 。在 JDK 11 中它是实验性功能,需要使用特定参数启用:
bash
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -jar YourApp.jar
2. 单文件源代码程序运行
对于只有一个 .java 文件的简单程序或脚本,现在可以直接运行,省去显式编译步骤 。
bash
# 假设文件名为 Hello.java
java Hello.java
JFR
JDK Flight Recorder(JFR)是一款集成在Java虚拟机(JVM)中的低开销性能监控和事件收集工具。它就像是Java应用的"黑匣子",能持续记录应用程序运行时的详细信息,帮助开发者进行性能分析和故障诊断。
下面是JFR的核心特性概要:
| 特性维度 | 具体说明 |
|---|---|
| 核心定位 | JVM 内置的低开销性能监控和事件记录器,适用于生产环境 。 |
| 核心价值 | 低开销 (通常<1%),深度集成 (可获取JVM内部细节),生产可用 (可长期运行) 。 |
| 核心功能 | 记录GC事件 、线程活动 、锁竞争 、I/O操作 、类加载 、JIT编译等大量事件 。 |
| 核心组件 | 事件系统 (内置事件和自定义事件)、记录机制 (内存缓冲区到磁盘文件)、配置文件 (如default.jfc和profile.jfc) 。 |
| 启动方式 | 命令行启动 (应用启动时)、动态开启 (使用jcmd命令,无需重启JVM) 。 |
| 数据分析 | 使用 Java Mission Control (JMC) 工具进行可视化分析 。 |
💡 核心概念与工作原理
理解JFR的以下几个核心概念,有助于你更好地使用它:
- 事件(Event):这是JFR的基石。JFR通过捕获JVM和应用程序运行过程中触发的各种"事件"来工作。事件类型丰富,例如线程的启动/停止、垃圾回收的发生、文件的读写、synchronized锁的竞争等,都有对应的事件。
- 记录文件(Recording) :JFR将捕获到的事件数据保存为后缀是
.jfr的文件。这个文件是后续分析的基础。 - 配置文件(JFC - JFR Configuration Files) :为了平衡开销和信息的详细程度,JFR使用配置文件来定义记录哪些事件以及记录的频率(采样率)。JDK通常自带两个常用的配置文件:
default.jfc:默认配置,开销极低(通常<1%) ,适合在生产环境中长时间连续运行。profile.jfc:分析配置,记录更详细 ,开销稍高(通常<2%),适合短时间的性能剖析。
- 环形缓冲区(Ring Buffer):JFR在内存中使用一种称为"环形缓冲区"的机制。事件先被写入线程本地缓冲区,然后被提升到全局的环形缓冲区。当缓冲区满时,最旧的事件会被新事件覆盖。这意味着你总是能获取到"最近一段时间"的数据,这对于诊断突发性问题非常有用。
🛠️ 启用与使用JFR
启用JFR非常灵活,主要有两种方式:
-
启动应用时开启 :在启动Java应用程序的命令行参数中直接指定。例如,以下命令会让JVM在启动后立即开始记录,持续1分钟,并将结果保存到
recording.jfr文件中。bashjava -XX:StartFlightRecording=delay=5s,duration=1m,name=MyAppRecording,filename=recording.jfr,settings=profile -jar myapp.jar参数说明:
delay=5s表示延迟5秒开始记录;duration=1m记录持续1分钟;name为记录会话命名;filename指定输出文件;settings=profile使用详细的性能分析配置。 -
运行时动态开启(更常用) :利用
jcmd工具,你可以在不重启JVM的情况下,随时对正在运行的Java进程开启记录。这对于诊断线上突然出现的问题至关重要。-
首先,使用
jcmd或jps -l找到目标Java进程的PID。 -
然后,执行命令开始记录:
bashjcmd <PID> JFR.start name=MyRecording duration=120s filename=/tmp/myrecording.jfr -
你还可以开启一个常驻的环形缓冲记录 ,用于持续监控,只在需要时才将数据导出:
bash# 开始一个最大保存30分钟数据或500MB数据的环形缓冲记录(不立即写文件) jcmd <PID> JFR.start name=ProdRing settings=default disk=true maxage=30m maxsize=500m # 当需要分析时,将最近的数据导出成文件 jcmd <PID> JFR.dump name=ProdRing filename=/path/to/dump.jfr
-
🔬 分析JFR记录文件
生成的 .jfr 文件需要使用 Java Mission Control (JMC) 工具打开进行分析。JMC提供了一个强大的图形化界面,让你能够直观地浏览和分析数据。
在JMC中,你可以重点查看以下视图:
- 概览/自动分析:JMC会提供一个初步的自动化分析报告,直接标出潜在的性能瓶颈(如GC时间过长、锁竞争激烈等),这是非常好的起点。
- 方法分析:找出CPU耗时最长的"热方法",这是性能优化的首要目标。
- 内存:查看对象分配速率、垃圾回收的详细行为和停顿时间,帮助诊断内存泄漏或GC问题。
- 线程:查看线程的状态(运行、阻塞、等待),识别锁竞争和线程瓶颈。
- I/O:分析套接字读写和文件操作的延迟。
💎 核心应用场景
- 线上性能问题排查:当应用出现慢请求、CPU飙高或周期性卡顿时,立即开启一段时间的JFR记录,通过JMC分析问题时间点附近的JVM内部状态。
- 内存泄漏诊断:结合对象分配事件和GC事件,追踪那些持续增长且不被回收的对象。
- GC调优验证:在调整JVM内存参数后,通过JFR记录GC停顿时间、频率和堆内存变化,验证调优效果。
- 建立性能基线:在应用平稳运行时录制一段JFR数据,作为性能"健康状态"的基准,便于后续对比。
⚠️ 注意事项
- 权限 :确保运行JVM的用户有权限在指定路径创建和写入
.jfr文件。 - 磁盘空间:长时间录制或高频率事件会产生较大的文件,注意监控磁盘空间。
- 数据敏感性:JFR记录可能包含应用的方法参数、SQL语句片段等敏感信息,共享和存储时需注意安全。
⚠️ 重要变更与升级注意事项
从 JDK 8 升级到 JDK 11 时,需要特别留意以下破坏性变更:
- 移除的模块:Java EE(如 JAX-WS, JAXB)和 CORBA 模块已被移除。如果项目用到这些技术,需要手动添加相关依赖 。
- JavaFX 分离:JavaFX 不再包含在 JDK 中,需要单独下载和引入 。
- 强封装内部 API :通过反射访问
sun.*等内部 API 会受到限制,可能需要使用--add-opens参数来解禁 。
💎 总结
JDK 11 的新特性侧重于开发效率的提升 和运行时性能的优化。字符串、HTTP Client、文件操作等 API 的增强让日常编码更简洁。ZGC、JFR 等则为高性能应用提供了强大工具。