LTS:LTS是Long-Term Support长期支持的缩写是 Oracle 及 OpenJDK 社区为企业级应用提供的「稳定版本保障」。非LTS版本每6个月发布一次更像是“尝鲜版”。它们包含最新的功能但官方支持周期很短通常只有6个月。适合个人开发者体验新特性。LTS版本大约每2-3年发布一次会获得长达数年的官方支持包括安全更新和错误修复。JDK 17作为LTS版本将获得至少8年的支持直到2029年9月这为企业提供了升级和长期运行的稳定基础。从 JDK 8 开始Java 确立了「每 6 个月发布一个非 LTS 版本每 3 年发布一个 LTS 版本」的迭代节奏JDK 8 LTS2014 年发布经典中的经典支撑了无数企业系统支持周期已接近尾声目前仅提供关键安全补丁JDK 11 LTS2018 年发布继 JDK 8 后的又一主流版本引入模块化雏形目前仍有大量企业在使用JDK 17 LTS2021 年发布沉淀了 JDK 9 到 JDK 16 的所有优秀特性性能、安全性、语法简洁度均远超 JDK 8/11JDK 21 LTS2023 年发布正在普及的版本在 JDK 17 基础上新增虚拟线程等特性未来将逐步替代 JDK 17。密封类Sealed Classes什么是密封类密封类是一种「限制继承关系」的类它可以明确指定「哪些子类可以继承自己」相当于给父类加了一个「继承白名单」避免无关子类随意继承导致的逻辑混乱。在 JDK 8 中我们定义一个父类后无法限制其他开发者随意创建子类尤其是在领域模型、状态机设计中很容易出现「继承泛滥」的问题。密封类的核心语法是sealed声明密封类和permits指定允许继承的子类子类必须显式声明为final/sealed/non-sealed三者之一。// 1. 密封类定义 public sealed class Shape permits Circle, Rectangle, Triangle { public double area() { return 0; } } // 2. 允许的子类必须是 final、sealed 或 non-sealed public final class Circle extends Shape { Override public double area() { return Math.PI * radius * radius; } } public final class Rectangle extends Shape { Override public double area() { return width * height; } } // 3. 密封接口 public sealed interface Vehicle permits Car, Truck { void drive(); } public final class Car implements Vehicle { public void drive() { System.out.println(Driving car); } }模式匹配Pattern Matching和增强的 switch 表达1. switch 支持模式匹配JDK 17 正式特性可以直接在 switch 中进行类型判断和变量声明无需手动强制转换。// JDK 17 之前的写法 public String format(Object obj) { if (obj instanceof Integer) { Integer i (Integer) obj; return 整数 i; } else if (obj instanceof String) { String s (String) obj; return 字符串 s; } else { return 未知类型; } } // JDK 17 的写法 - 使用 switch 模式匹配 public String format(Object obj) { return switch (obj) { case Integer i - 整数 i; case String s - 字符串 s; case Double d - 小数 d; default - 未知类型; }; }2. 箭头语法-简化代码更简洁的 lambda 风格语法自动返回值。// 传统 switch 写法 public int getDays(int month, int year) { int days; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days 31; break; case 4: case 6: case 9: case 11: days 30; break; case 2: days isLeapYear(year) ? 29 : 28; break; default: throw new IllegalArgumentException(无效的月份); } return days; } // JDK 17 增强写法 public int getDays(int month, int year) { return switch (month) { case 1, 3, 5, 7, 8, 10, 12 - 31; case 4, 6, 9, 11 - 30; case 2 - isLeapYear(year) ? 29 : 28; default - throw new IllegalArgumentException(无效的月份); }; }3. 合并多个 case 标签使用逗号分隔多个值更简洁。public String getSeason(String month) { return switch (month) { case 三月, 四月, 五月 - 春季; case 六月, 七月, 八月 - 夏季; case 九月, 十月, 十一月 - 秋季; case 十二月, 一月, 二月 - 冬季; default - 未知; }; }4. 不需要 break 语句箭头语法自动处理 break避免遗漏导致的穿透问题。// 传统写法容易忘记 break switch (day) { case MONDAY: System.out.println(周一); break; // 容易忘记 case TUESDAY: System.out.println(周二); break; } // JDK 17 写法 - 无需 break switch (day) { case MONDAY - System.out.println(周一); case TUESDAY - System.out.println(周二); case WEDNESDAY - System.out.println(周三); }5. 与密封类Sealed Classes完美配合当 switch 作用于密封类时如果覆盖所有子类可以省略 default。// 假设 Shape 是密封类 public sealed class Shape permits Circle, Rectangle, Triangle {} public final class Circle extends Shape {} public final class Rectangle extends Shape {} public final class Triangle extends Shape {} // 计算面积 - 无需 default编译器会检查是否完整 public double calculateArea(Shape shape) { return switch (shape) { case Circle c - Math.PI * c.radius() * c.radius(); case Rectangle r - r.width() * r.height(); case Triangle t - 0.5 * t.base() * t.height(); // 不需要 default编译器确保已覆盖所有情况 }; }简化的集合操作虽然 JDK 17 本身没有新增集合简化特性但它集成了之前版本的所有优秀特性JDK 8: Stream API、Lambda、默认方法JDK 9: of() 工厂方法、takeWhile/dropWhileJDK 10: var 局部变量类型推断JDK 16: toList()/toMap()/toSet() 简化// 场景 1数据过滤和转换 public ListString processUsers(ListUser users) { return users.stream() .filter(u - u.getAge() 18) .map(User::getName) .map(String::toUpperCase) .toList(); } // 场景 2分组统计 public MapString, Long countByDept(ListEmployee employees) { return employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.counting() )); } // 场景 3集合去重和排序 public ListProduct getUniqueProducts(ListProduct products) { return products.stream() .distinct() .sorted(Comparator.comparing(Product::getPrice).reversed()) .toList(); } // 场景 4Map 聚合计算 public void updateInventory(MapString, Integer inventory, ListItem items) { for (Item item : items) { inventory.merge(item.getCode(), item.getQuantity(), Integer::sum); } }文本块Text Blocks什么是文本块文本块使用三个双引号来包裹多行字符串无需手动添加换行符和转义字符。基本语法// 传统写法 - 需要拼接和转义 String html html\n body\n pHello World/p\n /body\n /html\n; // JDK 17 文本块写法 - 简洁清晰 String html html body pHello World/p /body /html ;主要特性1.自动处理换行无需手动添加 \n保持代码的自然格式。2.自动缩进处理编译器会自动去除每行开头的公共空白部分3.无需转义特殊字符可以直接包含双引号、反斜杠等。4.支持字符串模板可以嵌入变量和表达式。模块化系统JPMSJDK 17 中的模块化系统JPMS - Java Platform Module System也称为 Project Jigsaw是 Java 9 引入的一项革命性特性在 JDK 17 中已经非常成熟稳定。什么是 JPMSJPMS是一种将 Java 平台和相关应用程序划分为一组模块的机制目的是更强的封装性只暴露需要的类和方法清晰的依赖管理显式声明模块间的依赖关系更好的可维护性减少类路径冲突JAR Hell更小的运行时可以只包含需要的模块// 示例定义一个库存管理模块 module com.example.inventory { // 声明依赖的其他模块 requires java.sql; requires java.logging; // 导出的包外部可访问 exports com.example.inventory.service; exports com.example.inventory.model; // 开放的包允许反射访问 opens com.example.inventory.impl; // 使用的服务实现 uses com.example.inventory.provider.InventoryProvider; // 提供的服务实现 provides com.example.inventory.provider.InventoryProvider with com.example.inventory.provider.DatabaseInventoryProvider; }场景背景JDK 8 的痛点在 JDK 8 中我们所有的业务代码、引入的第三方 Jar 包比如 Spring、MyBatis都被一股脑地放在「类路径classpath」这个「大箱子」里开发和运维时会遇到 4 个让人头疼的问题类冲突最常见不同 Jar 包里有同名的类比如两个不同版本的工具包都有 com.example.utils.StringUtilsJVM 加载时不知道该选哪个直接抛出 ClassNotFoundException 或 NoClassDefFoundError排查起来要翻遍所有 Jar 包耗时耗力隐式依赖维护噩梦项目里用了某个 Jar 包的类但没有明确声明「我依赖这个 Jar 包」后续其他人接手项目、或部署到新环境时很容易漏掉这个依赖导致项目启动失败启动缓慢微服务痛点JVM 启动时会把类路径下所有的类都加载一遍哪怕有些类从头到尾都没被使用过比如某个 Jar 包的冷门功能不仅启动速度慢还占用大量内存在微服务场景下这个问题会被放大很多微服务需要快速启动、快速扩容无强封装耦合过高只要类是 public 修饰的其他任何代码都能访问它哪怕这个类是某个框架的内部实现类、不希望被外部调用这就导致项目之间耦合过高后续修改内部代码时很容易影响到外部调用者。垃圾收集器JDK 8 默认 GCParallel GC并行收集器G1 在 JDK 8 中是可选、非默认必须手动加 -XX:UseG1GC 才能启用。JDK 9 → JDK 17 官方默认 GCG1 GC从 JDK 9 开始OpenJDK 将默认 GC 从 Parallel GC 改为 G1 GC并一直延续到 JDK 17、JDK 18、JDK 19、JDK 20。JDK 17 官方默认仍然是 G1 GC不是 ZGC。ZGC 在 JDK 17 中的定位ZGC 在 JDK 15 已结束实验成为正式生产特性JDK 17 中 ZGC 是高可用、可生产的正式 GC但不是默认 GC必须通过 -XX:UseZGC 手动显式启用。JDK 21 开始ZGC 成为默认 GC 的版本从 JDK 21 开始OpenJDK 才将默认 GC 从 G1 改为 ZGC。什么是 ZGCZGCZ Garbage Collector是 Oracle 主导开发的一款可扩展、低延迟、高吞吐的垃圾收集器。JDK 8 Parallel GC并行垃圾回收器┌─────────────────────────────────────┐ │ Young Generation (Eden S0 S1) │ │ ─────────────────────────────── │ │ Minor GC: 多线程并行复制 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Old Generation │ │ Full GC: 标记 - 整理STW │ └─────────────────────────────────────┘JDK 17 G1 GCGarbage-First┌─────────────────────────────────────────────┐ │ Heap Regions (固定大小通常 1-32MB) │ │ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ E │ E │ S │ S │ O │ O │ H │ H │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ E │ E │ S │ S │ O │ O │ M │ M │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ │ │ EEden, SSurvivor, OOld, HHumongous │ │ MMetaspace │ └─────────────────────────────────────────────┘ 回收策略优先回收价值最大的 Region垃圾最多G1的四个阶段1. Young Collection年轻代回收 - STW并行收集 - Eden → Survivor/To Space 2. Concurrent Marking并发标记 - 与应用程序并发执行 - 标记存活对象 3. Remark最终标记 - STW处理并发期间的变化 - 使用 SATB 算法 4. Cleanup清理 - STW 并发 - 回收空 Region统计存活数据JDK 17 ZGCZ Garbage Collector┌─────────────────────────────────────────────┐ │ ZGC 并发周期 │ │ │ │ 1. Marking (并发) │ │ ├─ Mark Stack Scan │ │ └─ Object Scan │ │ │ │ 2. Reference Processing (并发) │ │ │ │ 3. Remap (并发 短暂 STW) │ │ ├─ Relocate Live Objects │ │ └─ Update References (Load Barriers) │ │ │ │ 停顿时间 1ms几乎无感知 │ └─────────────────────────────────────────────┘核心技术1. Colored Pointers染色指针 - 64 位指针中用几位标记对象状态 - 无需额外内存记录引用信息 2. Load Barriers读屏障 - 对象访问时检查并更新引用 - 并发重映射 3. Region 分层 - Small (256KB) - Large (≥256KB)
JDK17 新特性
LTS:LTS是Long-Term Support长期支持的缩写是 Oracle 及 OpenJDK 社区为企业级应用提供的「稳定版本保障」。非LTS版本每6个月发布一次更像是“尝鲜版”。它们包含最新的功能但官方支持周期很短通常只有6个月。适合个人开发者体验新特性。LTS版本大约每2-3年发布一次会获得长达数年的官方支持包括安全更新和错误修复。JDK 17作为LTS版本将获得至少8年的支持直到2029年9月这为企业提供了升级和长期运行的稳定基础。从 JDK 8 开始Java 确立了「每 6 个月发布一个非 LTS 版本每 3 年发布一个 LTS 版本」的迭代节奏JDK 8 LTS2014 年发布经典中的经典支撑了无数企业系统支持周期已接近尾声目前仅提供关键安全补丁JDK 11 LTS2018 年发布继 JDK 8 后的又一主流版本引入模块化雏形目前仍有大量企业在使用JDK 17 LTS2021 年发布沉淀了 JDK 9 到 JDK 16 的所有优秀特性性能、安全性、语法简洁度均远超 JDK 8/11JDK 21 LTS2023 年发布正在普及的版本在 JDK 17 基础上新增虚拟线程等特性未来将逐步替代 JDK 17。密封类Sealed Classes什么是密封类密封类是一种「限制继承关系」的类它可以明确指定「哪些子类可以继承自己」相当于给父类加了一个「继承白名单」避免无关子类随意继承导致的逻辑混乱。在 JDK 8 中我们定义一个父类后无法限制其他开发者随意创建子类尤其是在领域模型、状态机设计中很容易出现「继承泛滥」的问题。密封类的核心语法是sealed声明密封类和permits指定允许继承的子类子类必须显式声明为final/sealed/non-sealed三者之一。// 1. 密封类定义 public sealed class Shape permits Circle, Rectangle, Triangle { public double area() { return 0; } } // 2. 允许的子类必须是 final、sealed 或 non-sealed public final class Circle extends Shape { Override public double area() { return Math.PI * radius * radius; } } public final class Rectangle extends Shape { Override public double area() { return width * height; } } // 3. 密封接口 public sealed interface Vehicle permits Car, Truck { void drive(); } public final class Car implements Vehicle { public void drive() { System.out.println(Driving car); } }模式匹配Pattern Matching和增强的 switch 表达1. switch 支持模式匹配JDK 17 正式特性可以直接在 switch 中进行类型判断和变量声明无需手动强制转换。// JDK 17 之前的写法 public String format(Object obj) { if (obj instanceof Integer) { Integer i (Integer) obj; return 整数 i; } else if (obj instanceof String) { String s (String) obj; return 字符串 s; } else { return 未知类型; } } // JDK 17 的写法 - 使用 switch 模式匹配 public String format(Object obj) { return switch (obj) { case Integer i - 整数 i; case String s - 字符串 s; case Double d - 小数 d; default - 未知类型; }; }2. 箭头语法-简化代码更简洁的 lambda 风格语法自动返回值。// 传统 switch 写法 public int getDays(int month, int year) { int days; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days 31; break; case 4: case 6: case 9: case 11: days 30; break; case 2: days isLeapYear(year) ? 29 : 28; break; default: throw new IllegalArgumentException(无效的月份); } return days; } // JDK 17 增强写法 public int getDays(int month, int year) { return switch (month) { case 1, 3, 5, 7, 8, 10, 12 - 31; case 4, 6, 9, 11 - 30; case 2 - isLeapYear(year) ? 29 : 28; default - throw new IllegalArgumentException(无效的月份); }; }3. 合并多个 case 标签使用逗号分隔多个值更简洁。public String getSeason(String month) { return switch (month) { case 三月, 四月, 五月 - 春季; case 六月, 七月, 八月 - 夏季; case 九月, 十月, 十一月 - 秋季; case 十二月, 一月, 二月 - 冬季; default - 未知; }; }4. 不需要 break 语句箭头语法自动处理 break避免遗漏导致的穿透问题。// 传统写法容易忘记 break switch (day) { case MONDAY: System.out.println(周一); break; // 容易忘记 case TUESDAY: System.out.println(周二); break; } // JDK 17 写法 - 无需 break switch (day) { case MONDAY - System.out.println(周一); case TUESDAY - System.out.println(周二); case WEDNESDAY - System.out.println(周三); }5. 与密封类Sealed Classes完美配合当 switch 作用于密封类时如果覆盖所有子类可以省略 default。// 假设 Shape 是密封类 public sealed class Shape permits Circle, Rectangle, Triangle {} public final class Circle extends Shape {} public final class Rectangle extends Shape {} public final class Triangle extends Shape {} // 计算面积 - 无需 default编译器会检查是否完整 public double calculateArea(Shape shape) { return switch (shape) { case Circle c - Math.PI * c.radius() * c.radius(); case Rectangle r - r.width() * r.height(); case Triangle t - 0.5 * t.base() * t.height(); // 不需要 default编译器确保已覆盖所有情况 }; }简化的集合操作虽然 JDK 17 本身没有新增集合简化特性但它集成了之前版本的所有优秀特性JDK 8: Stream API、Lambda、默认方法JDK 9: of() 工厂方法、takeWhile/dropWhileJDK 10: var 局部变量类型推断JDK 16: toList()/toMap()/toSet() 简化// 场景 1数据过滤和转换 public ListString processUsers(ListUser users) { return users.stream() .filter(u - u.getAge() 18) .map(User::getName) .map(String::toUpperCase) .toList(); } // 场景 2分组统计 public MapString, Long countByDept(ListEmployee employees) { return employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.counting() )); } // 场景 3集合去重和排序 public ListProduct getUniqueProducts(ListProduct products) { return products.stream() .distinct() .sorted(Comparator.comparing(Product::getPrice).reversed()) .toList(); } // 场景 4Map 聚合计算 public void updateInventory(MapString, Integer inventory, ListItem items) { for (Item item : items) { inventory.merge(item.getCode(), item.getQuantity(), Integer::sum); } }文本块Text Blocks什么是文本块文本块使用三个双引号来包裹多行字符串无需手动添加换行符和转义字符。基本语法// 传统写法 - 需要拼接和转义 String html html\n body\n pHello World/p\n /body\n /html\n; // JDK 17 文本块写法 - 简洁清晰 String html html body pHello World/p /body /html ;主要特性1.自动处理换行无需手动添加 \n保持代码的自然格式。2.自动缩进处理编译器会自动去除每行开头的公共空白部分3.无需转义特殊字符可以直接包含双引号、反斜杠等。4.支持字符串模板可以嵌入变量和表达式。模块化系统JPMSJDK 17 中的模块化系统JPMS - Java Platform Module System也称为 Project Jigsaw是 Java 9 引入的一项革命性特性在 JDK 17 中已经非常成熟稳定。什么是 JPMSJPMS是一种将 Java 平台和相关应用程序划分为一组模块的机制目的是更强的封装性只暴露需要的类和方法清晰的依赖管理显式声明模块间的依赖关系更好的可维护性减少类路径冲突JAR Hell更小的运行时可以只包含需要的模块// 示例定义一个库存管理模块 module com.example.inventory { // 声明依赖的其他模块 requires java.sql; requires java.logging; // 导出的包外部可访问 exports com.example.inventory.service; exports com.example.inventory.model; // 开放的包允许反射访问 opens com.example.inventory.impl; // 使用的服务实现 uses com.example.inventory.provider.InventoryProvider; // 提供的服务实现 provides com.example.inventory.provider.InventoryProvider with com.example.inventory.provider.DatabaseInventoryProvider; }场景背景JDK 8 的痛点在 JDK 8 中我们所有的业务代码、引入的第三方 Jar 包比如 Spring、MyBatis都被一股脑地放在「类路径classpath」这个「大箱子」里开发和运维时会遇到 4 个让人头疼的问题类冲突最常见不同 Jar 包里有同名的类比如两个不同版本的工具包都有 com.example.utils.StringUtilsJVM 加载时不知道该选哪个直接抛出 ClassNotFoundException 或 NoClassDefFoundError排查起来要翻遍所有 Jar 包耗时耗力隐式依赖维护噩梦项目里用了某个 Jar 包的类但没有明确声明「我依赖这个 Jar 包」后续其他人接手项目、或部署到新环境时很容易漏掉这个依赖导致项目启动失败启动缓慢微服务痛点JVM 启动时会把类路径下所有的类都加载一遍哪怕有些类从头到尾都没被使用过比如某个 Jar 包的冷门功能不仅启动速度慢还占用大量内存在微服务场景下这个问题会被放大很多微服务需要快速启动、快速扩容无强封装耦合过高只要类是 public 修饰的其他任何代码都能访问它哪怕这个类是某个框架的内部实现类、不希望被外部调用这就导致项目之间耦合过高后续修改内部代码时很容易影响到外部调用者。垃圾收集器JDK 8 默认 GCParallel GC并行收集器G1 在 JDK 8 中是可选、非默认必须手动加 -XX:UseG1GC 才能启用。JDK 9 → JDK 17 官方默认 GCG1 GC从 JDK 9 开始OpenJDK 将默认 GC 从 Parallel GC 改为 G1 GC并一直延续到 JDK 17、JDK 18、JDK 19、JDK 20。JDK 17 官方默认仍然是 G1 GC不是 ZGC。ZGC 在 JDK 17 中的定位ZGC 在 JDK 15 已结束实验成为正式生产特性JDK 17 中 ZGC 是高可用、可生产的正式 GC但不是默认 GC必须通过 -XX:UseZGC 手动显式启用。JDK 21 开始ZGC 成为默认 GC 的版本从 JDK 21 开始OpenJDK 才将默认 GC 从 G1 改为 ZGC。什么是 ZGCZGCZ Garbage Collector是 Oracle 主导开发的一款可扩展、低延迟、高吞吐的垃圾收集器。JDK 8 Parallel GC并行垃圾回收器┌─────────────────────────────────────┐ │ Young Generation (Eden S0 S1) │ │ ─────────────────────────────── │ │ Minor GC: 多线程并行复制 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Old Generation │ │ Full GC: 标记 - 整理STW │ └─────────────────────────────────────┘JDK 17 G1 GCGarbage-First┌─────────────────────────────────────────────┐ │ Heap Regions (固定大小通常 1-32MB) │ │ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ E │ E │ S │ S │ O │ O │ H │ H │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ E │ E │ S │ S │ O │ O │ M │ M │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ │ │ EEden, SSurvivor, OOld, HHumongous │ │ MMetaspace │ └─────────────────────────────────────────────┘ 回收策略优先回收价值最大的 Region垃圾最多G1的四个阶段1. Young Collection年轻代回收 - STW并行收集 - Eden → Survivor/To Space 2. Concurrent Marking并发标记 - 与应用程序并发执行 - 标记存活对象 3. Remark最终标记 - STW处理并发期间的变化 - 使用 SATB 算法 4. Cleanup清理 - STW 并发 - 回收空 Region统计存活数据JDK 17 ZGCZ Garbage Collector┌─────────────────────────────────────────────┐ │ ZGC 并发周期 │ │ │ │ 1. Marking (并发) │ │ ├─ Mark Stack Scan │ │ └─ Object Scan │ │ │ │ 2. Reference Processing (并发) │ │ │ │ 3. Remap (并发 短暂 STW) │ │ ├─ Relocate Live Objects │ │ └─ Update References (Load Barriers) │ │ │ │ 停顿时间 1ms几乎无感知 │ └─────────────────────────────────────────────┘核心技术1. Colored Pointers染色指针 - 64 位指针中用几位标记对象状态 - 无需额外内存记录引用信息 2. Load Barriers读屏障 - 对象访问时检查并更新引用 - 并发重映射 3. Region 分层 - Small (256KB) - Large (≥256KB)