真实面经题目 · 原创解析

了解哪些不同 JDK 版本的新特性?

这道题考察的不是背版本号,而是能否把 JDK 演进和工程实践联系起来。回答时应先按主线概括:JDK 8 是现代 Java 的分水岭,引入 Lambda、Stream、Optional、默认方法和新的日期时间 API;JDK 9 到 10 开始模块化、集合工厂方法、JShell、接口私有方法和局部变量类型推断;JDK 11 作为常用长期支持版本,补齐 HTTP Client、字符串和文件 API、ZGC 初步可用等能力;JDK 17 是当前大量生产系统升级的关键长期支持版本,带来 sealed class、record、switch 表达式、文本块、模式匹配等语言能力,并强化 JVM、GC 和封装边界;JDK 21 进一步把虚拟线程、结构化并发、模式匹配 switch、record pattern、分代 ZGC 等特性推向成熟,重点提升高并发服务的线程模型和表达能力。

出现于:阿里巴巴 · 后端开发

60 秒回答模板

可以按“版本阶段 + 代表特性 + 工程影响”的方式回答。JDK 8 是最重要的基础版本,核心变化是函数式编程能力,包括 Lambda、Stream、Optional、接口默认方法和新的 java.time 日期时间 API,让 Java 代码从命令式循环逐步转向声明式处理,也让集合处理、异步回调和时间处理更清晰。JDK 9 的标志是模块系统 JPMS,同时引入 JShell、集合工厂方法、接口私有方法和 G1 成为默认垃圾收集器,它更关注大型应用的依赖边界、JDK 内部 API 收敛和运行时镜像裁剪。JDK 10 的代表是 var 局部变量类型推断,主要改善局部变量声明的冗余,但不会改变 Java 的静态类型本质。JDK 11 是很多企业从 8 升级的常见落点,长期支持属性更强,HTTP Client 标准化,String、Files、Optional 等 API 增强,同时移除 Java EE、CORBA 等历史模块,升级时要重点关注依赖兼容。JDK 17 是另一个常见生产长期支持版本,语言层面有 record、sealed class、switch 表达式、文本块、instanceof 模式匹配等,能显著减少样板代码并提高建模能力;运行时层面也有更严格的强封装和更多 GC 选择。JDK 21 的重点是虚拟线程正式可用、模式匹配能力继续完善、分代 ZGC 改进低延迟回收场景,它适合讨论高并发阻塞式服务如何降低线程成本,但也不能把虚拟线程理解成万能性能优化,仍然要关注数据库连接池、锁竞争、ThreadLocal、限流和阻塞点。

考点 整体回答思路
主线 JDK 8:现代 Java 的分水岭
易错点 只按版本号罗列特性,不说明解决的问题和工程影响。

深入解析

01

整体回答思路

面试官问“了解哪些不同 JDK 版本的新特性”,通常不只是考记忆,而是考候选人是否理解 Java 技术栈的演进。成熟回答应抓住工程上最常见的版本节点:JDK 8、9、10、11、17、21。每个节点都要讲清三件事:它引入了哪些代表特性,这些特性解决了什么问题,它对真实工程有什么影响,比如代码风格变化、依赖升级风险、性能调优方式、运行时参数变化、容器化部署影响以及团队迁移成本。

02

JDK 8:现代 Java 的分水岭

JDK 8 是现代 Java 编程风格的起点。最重要的是 Lambda 表达式、函数式接口、Stream API、Optional、接口默认方法和新的日期时间 API。Lambda 和函数式接口让行为可以作为参数传递;Stream API 让集合处理从外部迭代转向声明式流水线;Optional 用来表达“可能没有值”,但更适合作为返回值而不是字段或入参;接口默认方法让接口演进时可以增加方法而不强制所有实现类立刻改动;java.time 替代 Date、Calendar 的大量缺陷,提供不可变、线程安全、语义清晰的时间类型。工程上要警惕滥用 Stream、过度链式调用、Optional 使用不当和 parallelStream 误用。

03

JDK 9:模块化和工程边界

JDK 9 的核心特性是 JPMS 模块系统。它通过 module-info.java 显式声明 requires 和 exports,让依赖关系更清楚,也为 jlink 裁剪运行时镜像提供基础。JDK 9 还引入 JShell、List.of、Set.of、Map.of 等集合工厂方法,接口私有方法可以抽取默认方法之间的复用逻辑,G1 也成为默认垃圾收集器。工程影响上,JDK 9 之后对 JDK 内部 API 的封装逐步加强,很多老项目依赖 sun.misc、反射访问 JDK 内部类或使用老旧字节码工具时,升级会暴露兼容问题。

04

JDK 10:var 和小步演进

JDK 10 最常被提到的是局部变量类型推断 var。它只适用于局部变量,编译器仍然会在编译期推断出明确类型,Java 仍是静态强类型语言。var 的价值在于减少重复类型声明,尤其是泛型嵌套较深或右侧构造表达式已经能清晰表达类型时。但它也可能降低可读性,例如变量名不清楚、右侧是复杂方法调用、业务语义依赖显式类型时,不应为了简写而使用 var。

05

JDK 11:常见长期支持升级目标

JDK 11 是很多企业从 JDK 8 升级时会考虑的长期支持版本。代表特性包括标准化 HTTP Client、String API 增强、Files API 增强、Optional 和集合相关 API 增强,以及单文件源码运行等。HTTP Client 支持同步、异步和 HTTP/2;String 增加 isBlank、lines、strip、repeat 等方法;Files 增加 readString、writeString 等便利方法。JDK 11 也移除了 Java EE、CORBA 等历史模块,这会影响依赖 JAXB、JAX-WS 等旧能力的项目,需要显式引入外部依赖。

06

JDK 17:生产升级的重要长期支持版本

JDK 17 是近年来生产系统常见的长期支持版本之一。record 用来表达不可变数据载体,适合 DTO、值对象、查询结果等场景,但不适合承载复杂领域行为的富模型;sealed class 可以限制继承层级,让类型体系更可控;switch 表达式减少传统 fall-through 带来的错误;文本块让多行 SQL、JSON、HTML 片段更易读;instanceof 模式匹配减少强制类型转换样板代码。运行时方面,JDK 17 对 JDK 内部 API 的强封装更严格,迁移前必须评估框架版本、构建链路、运行参数和三方依赖。

07

JDK 21:高并发和模式匹配的进一步成熟

JDK 21 的重点是把一些对工程实践影响很大的能力推向成熟。虚拟线程让阻塞式编程模型可以用更低成本承载大量并发任务,尤其适合网络 IO、数据库访问、远程调用这类等待时间较多的服务。但虚拟线程不是万能优化:如果瓶颈在数据库连接池、下游吞吐、CPU 密集计算、锁竞争、全局限流或长时间持有 synchronized 锁,单纯换虚拟线程并不能解决问题。JDK 21 还包括 record pattern、switch 模式匹配等特性,分代 ZGC 则进一步增强低延迟垃圾回收在不同对象生命周期下的适应能力。

08

分类记忆方式

更好的记忆方式是按类别而不是按版本硬背。语言层面包括 Lambda、var、record、sealed class、switch 表达式、文本块、模式匹配;标准库层面包括 Stream、Optional、java.time、集合工厂方法、HTTP Client、String 和 Files 增强;JVM 和 GC 层面包括 G1 默认化、ZGC、Shenandoah、低延迟回收、容器感知、类数据共享等;工程化层面包括模块系统、jlink、自定义运行时镜像、强封装、依赖迁移、构建工具兼容、监控探针兼容。

09

迁移视角

如果继续追问从 JDK 8 升级到 17 或 21,要从四个层面回答。编译和构建层面,检查 Maven、Gradle、编译插件、测试插件、代码生成工具、静态检查工具是否支持目标 JDK;依赖层面,升级 Spring、Netty、Byte Buddy、ASM、Mockito、Lombok、数据库驱动、日志框架、监控 Agent 等可能触碰字节码或反射的组件;运行时层面,检查 GC 参数是否废弃、默认 GC 行为是否变化、容器内存和 CPU 识别是否符合预期、TLS 和加密算法是否受影响;业务回归层面,压测启动时间、吞吐、延迟、内存、Full GC 情况、接口兼容和序列化反序列化行为。

易错点

  • 只按版本号罗列特性,不说明解决的问题和工程影响。
  • 把 var 说成动态类型,忽略 Java 仍然是静态强类型语言。
  • 把 Optional 当作彻底消灭空指针的工具,甚至建议到处用 Optional 字段和参数。
  • 认为 parallelStream 一定能提升性能,忽略线程池、公用 ForkJoinPool、任务粒度和阻塞操作。
  • 只记得 JDK 9 的集合工厂方法,漏掉模块系统这个核心变化。
  • 把 record 当成 Lombok 或普通类的完全替代品,忽略不可变数据载体的定位。
  • 把 sealed class 只理解成语法糖,不知道它用于限制继承层级和表达封闭类型集合。
  • 认为升级 JDK 只需要改编译版本,忽略构建插件、字节码工具、反射、监控 Agent、GC 参数和历史模块移除。
  • 把虚拟线程吹成万能性能优化,忽略数据库连接池、下游吞吐、锁竞争和 CPU 密集任务瓶颈。
  • 回答时只强调最新版本,不能解释为什么生产环境常选择长期支持版本。

面试官追问

JDK 8 的 Lambda 和 Stream 有什么区别?

Lambda 是一种表达行为的语法形式,通常配合函数式接口使用;Stream 是集合和数据流处理 API,提供 filter、map、reduce、collect 等操作。Lambda 可以作为 Stream 操作的参数,但 Lambda 不等于 Stream。工程上,Lambda 解决代码冗余和行为传递问题,Stream 解决集合处理的声明式表达问题。

Optional 的正确使用方式是什么?

Optional 更适合作为方法返回值,用来显式表达结果可能为空,提醒调用方处理缺失场景。不建议把 Optional 作为实体字段、方法参数或集合元素大量使用,否则会增加序列化、框架绑定和代码理解成本。也不应该用 Optional.get 直接取值而不判断,这样只是把空指针风险换成另一种异常。

为什么说 JDK 9 的模块化对老项目影响大?

因为模块化加强了依赖边界和 JDK 内部 API 的封装。很多老项目或老框架可能通过反射访问内部类,或者依赖 sun.misc 等非标准 API。升级后这些行为可能出现警告、失败或需要额外启动参数。因此模块化带来的挑战主要是生态兼容和依赖治理。

JDK 11 相比 JDK 8,面试中最值得说哪些变化?

可以说标准 HTTP Client、String 和 Files API 增强、单文件源码运行、运行时和 GC 改进,以及历史模块移除。更重要的是指出从 8 到 11 的升级风险,包括 Java EE 相关模块移除、三方依赖兼容、构建插件版本、反射访问、GC 参数变化和监控 Agent 适配。

record 能不能完全替代普通类?

不能。record 适合表达以数据为中心、不可变、字段固定的值对象或 DTO。它自动生成构造器、访问器、equals、hashCode 和 toString,能减少样板代码。但如果对象需要复杂可变状态、继承普通类、复杂生命周期或丰富领域行为,普通类仍然更合适。

sealed class 的使用场景是什么?

sealed class 适合表达有限且可控的类型层级,例如业务结果、状态机状态、指令类型、事件类型等。它可以限制哪些类能够继承或实现某个父类型,让编译器和维护者更容易理解完整的类型集合,也能和 switch 模式匹配形成更安全的分支处理。

虚拟线程和线程池是什么关系?

虚拟线程不是传统意义上为了复用昂贵平台线程而设计的固定线程池。它的创建和阻塞成本更低,适合一请求一虚拟线程的阻塞式编程模型。但底层仍由 JVM 调度到平台线程执行。使用虚拟线程时,仍要控制外部资源并发,例如数据库连接、下游接口、文件句柄和限流策略。

虚拟线程适合 CPU 密集型任务吗?

不适合把虚拟线程当成 CPU 密集型任务的加速器。CPU 密集型任务的瓶颈是核心数和计算量,创建更多虚拟线程不会让 CPU 变多,反而可能增加调度开销。虚拟线程更适合大量等待 IO 的任务。

从 JDK 8 升级到 JDK 17 应该怎么验证?

应先升级构建工具和关键依赖,再解决编译期问题,然后做单元测试、集成测试和回归测试。运行时要检查启动参数、GC 日志、内存占用、延迟、吞吐、序列化、反射访问、监控 Agent 和容器资源识别。最后通过压测比较升级前后的性能指标,而不是只看应用能否启动。