JDK 17 升级到 JDK 21 的变更汇总

JDK 17 到 JDK 21 跨越了 JDK 18、19、20 三个非 LTS 版本。本文汇总这四个版本引入的重要变更,重点关注 breaking change 和需要主动迁移的部分。 JDK 18(2022 年 3 月) Breaking Change UTF-8 成为默认字符集(JEP 400) 这是 17 → 21 迁移中最常见的隐性 breaking change。JDK 18 起,Charset.defaultCharset() 固定返回 UTF-8,不再跟随操作系统区域设置。 受影响的场景: new String(bytes) — 未指定编码,依赖平台默认值 new FileReader(file) — 未指定编码 System.out.println() 输出非 ASCII 字符 读写文件时未显式指定编码 对 Linux 生产环境的实际影响 大多数现代 Linux 发行版默认 locale 是 en_US.UTF-8 或 zh_CN.UTF-8,JDK 17 在这类环境下默认字符集本来就是 UTF-8,因此 JDK 18 的这一变更对标准 Linux 服务器基本无感。 真正有风险的场景: Windows 开发/测试环境 — Windows 默认编码是 GBK/CP936,本地测试通过但部署到 Linux 后行为不同 精简容器镜像 — 某些极简 Docker 镜像不设置 locale,LANG 为空,JDK 17 此时默认字符集可能是 US-ASCII,升级到 JDK 18 后反而统一成了 UTF-8 遗留系统 — 有意依赖 GBK 平台编码处理中文数据(如读老数据库导出文件)的项目会出问题 修复方式:所有涉及字节/字符转换的地方显式指定 StandardCharsets.UTF_8。 ...

2026-05-13 · 3 min · 625 words · -

JDK 17 新特性

概述 JDK 17 是 Java 的长期支持版本(LTS),于 2021 年 9 月发布。相比 JDK 16,JDK 17 引入了多项新特性和改进,同时也包含了一些孵化特性的正式毕业版本。 正式特性(JEP) JEP 306: 恢复始终严格的浮点语义 将浮点运算恢复为始终严格模式(strict),删除了 strictfp 关键字的限制效果。在历史上,Java 曾因不同硬件平台的差异引入了扩展精度模式,随着现代硬件的普及,该差异不再存在,因此恢复了一致的浮点行为。 JEP 356: 增强型伪随机数生成器 提供新的接口和实现用于伪随机数生成器(PRNG),新增了 RandomGenerator 接口和多个算法实现,如 Xoshiro256PlusPlus、L64X128MixRandom 等。 RandomGenerator generator = RandomGeneratorFactory.of("L64X128MixRandom").create(); int randomInt = generator.nextInt(100); JEP 382: 新的 macOS 渲染管道 使用 Apple Metal API 实现 Java 2D 渲染管道,替代已废弃的 OpenGL API,提升在 macOS 上的图形渲染性能。 JEP 391: macOS/AArch64 移植 将 JDK 移植到 macOS/AArch64(Apple Silicon)平台,支持原生运行于 M1 及后续芯片的 Mac 电脑。 JEP 398: 废弃 Applet API 正式废弃 Applet API,标记为 @Deprecated(forRemoval = true)。浏览器早已不再支持 Java 插件,该 API 已无实际用途。 ...

2026-04-25 · 3 min · 560 words · -

JDK 8 新特性

JDK 8 相对于 JDK 7 引入的主要新特性: Lambda 表达式 函数式接口(Functional Interface) Stream API 方法引用(Method Reference) 默认方法(Default Method) Optional 新的日期时间 API(java.time) Nashorn JavaScript 引擎 Base64 并发增强(CompletableFuture、StampedLock、LongAdder) 重复注解(Repeating Annotations) 类型注解(Type Annotations) PermGen 移除,改用 Metaspace Lambda 表达式 Lambda 来自数学中的 λ 演算(Lambda Calculus),是函数式编程的理论基础。函数式编程的核心思想是:函数是"一等公民",可以像普通值一样被传递、赋值、返回。JDK 8 引入 Lambda,本质上是给 Java 这门面向对象语言加入了函数式编程的能力。 Lambda 表达式允许将函数(即 Lambda 表达式本身)作为参数传递,简化匿名内部类的写法。 语法结构 (参数列表) -> 方法体 (参数列表):传入的参数,无参数时写空括号 () ->:箭头操作符,读作 “goes to”,分隔参数列表和方法体 方法体:要执行的逻辑 Runnable 是一个接口(java.lang.Runnable),只有一个无参方法 void run(),因此参数列表为空 ()。 // JDK 7:匿名内部类写法 Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello"); } }; // JDK 8:Lambda 写法,箭头右边等价于 run() 的方法体 Runnable r = () -> System.out.println("Hello"); 将函数作为参数传递 JDK 8 之前,Java 无法直接传递"一段逻辑",只能把逻辑包装成匿名对象再传递。Lambda 表达式让你可以直接把逻辑作为参数传入方法,这就是"将函数作为参数传递"的含义。 ...

2026-04-25 · 3 min · 431 words · -