本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
Java 的 Valhalla 项目终于对 null 动手了,JEP 8303099 将终结 NPE 空指针异常。
Java 程序员苦 null 空异常久矣,尤其是初学者,经常会陷入到空异常里。
据统计,80% 以上的生产问题,都是有 null 这类 NPE 空指针异常造成的。不止 Java 语言有这方面的疼苦,其它语言也存在空指针问题。Java 团队在听取社区吐槽后,推出了 Optional,而这个用法遭同样也受到了大量用户“鸡肋”标签的吐槽。
为此,我也写了不少与此相关的文章,包括《https://mp.weixin.qq.com/s/Ard-MCSFITVcvyL71XQchQ》、《https://mp.weixin.qq.com/s/OX5VY70-pmra6XT0wa-27g》、《https://mp.weixin.qq.com/s/gdvGqd0NSae9Y1vne99uVQ》等。甚至是 Spring 等框架也在推进预防相关空异常《https://mp.weixin.qq.com/s/8KDYRmu1j8wMV0PmBd_Ong》的问题。
巧的是,我最近在社区里看到又有人在讨论#业余草 JEP 8303099这个提案。Java 的这个草案正在通过 Project Valhalla 引入一种全新的语言特性不可空类型(Null-Restricted Types),以从根本上解决困扰开发者数十年的#NullPointerException问题。
所以,接下来,我将深入解读 JEP 8303099 的设计动机、语法形式、运行时行为及其与值类型(Value Types)的深度协同,大家一起来理解这一重大变革。
为什么 Java 需要不可空类型?
Tony Hoare 曾将 null 称为“十亿美元错误”(Billion-Dollar Mistake)。要知道在 Java 中,任何引用类型变量都可能为null,而这种不确定性是无数运行时异常和逻辑 bug 的根源。
尽管社区已有多种方案,如@NonNull注解、Checker Framework、JSpecify 等,但它们都只是编译期辅助工具,无法在语言层面提供强保证,也无法影响运行时行为。
Project Valhalla 的目标不仅是提升性能(通过值类型和原语特化),更是要重塑 Java 的类型系统。而不可空类型,正是其中关键一环。
它或许能让 Java 彻底告别“10 亿美元错误”。
什么是不可空类型?
JEP 8303099(草案状态)正式提出了“Null-Restricted and Nullable Types (Preview)”特性。它的核心是内容引入两种空值标记(nullness markers)。
T!:不可空类型(Null-Restricted),表示该类型的值绝不能为null。T?:可空类型(Nullable),表示该类型明确允许null。T(无标记):空值未指定(Unspecified),即传统 Java 行为,兼容现有代码。
示例语法
String! name; // 不可空字符串,不能赋 null
String? title; // 可空字符串,可以赋 null
String desc; // 传统写法,空值语义未指定
这与 Kotlin 的 String / String? 恰好相反。Kotlin 默认非空,而 Java 默认“未指定”,以保证最大兼容性。
要解决的核心问题
消除意外的 null
开发者可以显式声明意图,这个字段、参数、返回值是否应该接受null。编译器和运行时将共同协作,防止违反约定。
支持值类型的“扁平化”优化
Valhalla 的值类型(Value Class)旨在消除对象头开销,实现“内联存储”(flattening)。但如果一个值类型字段可以为null,JVM 就必须额外保留一个 bit 来标记 null 状态,破坏了内存布局的紧凑性。
通过 MyValue! 声明不可空,JVM 就能安全地进行极致优化。
增强模式匹配
增强模式匹配,以及 switch 的 exhaustiveness。
在 Amber 项目中,switch表达式的穷尽性检查会受到null的影响。明确的空值类型能让编译器做出更精确的判断。
关键机制详解
下面,我们稍微展开一下这其中的关键机制。
初始化保证
不可空字段必须在使用前被初始化,否则编译报错。
class Person {
private String! name; // 必须初始化
public Person(String name) {
this.name = name; // 在 super() 前完成
super();
}
}
静态字段和数组同理,未初始化的不可空数组组件会导致运行时异常。
空值转换(Nullness Conversion)
- 宽化转换(Widening):
T!→T或T?,安全,无警告。 - 窄化转换(Narrowing):
T?→T!,编译器自动插入运行时检查,若值为null则抛出NullPointerException。
String? s = null;
// 编译通过,但运行时抛 NPE
String! t = s;
这种设计类似于自动装箱、拆箱,但增加了空安全语义。
泛型与反射支持
- 泛型参数也可带空值标记:
List<String!>。 - 反射 API 新增
RuntimeType,用于描述运行时实际的空值约束。 javadoc将显示空值标记,提升 API 文档清晰度。
当前进展与未来展望
- 状态:JEP 8303099 目前仍为 Draft(草案),尚未集成到任何正式 JDK 版本中。
- 依赖:该特性依赖于
Flexible Constructor Bodies(已在 JDK 24 Preview)等前置 JEP。 - 路线图:预计将在 JDK 27 或 JDK 28 中作为
Preview Feature首次亮相。 - 社区反馈:OpenJDK Valhalla 邮件列表正在积极讨论细节,欢迎开发者参与测试早期原型(如 LW5)。
总之,是一个好的兆头,但也存在跳票的可能。
结语
不可空类型不是为了“消灭null”或彻底抛弃 null,而是为了让null的存在变得可控、可预期、可验证。它代表了 Java 在保持向后兼容的前提下,向现代类型系统迈出的关键一步。
这对于广大 Java 开发者而言,不仅意味着更少的 NPE,更意味着更清晰的 API 设计、更强的性能潜力,以及一个更安全、更高效的未来。期待这个特性早日上新!
参考资料
- JEP 8303099 官方草案
https://openjdk.org/jeps/8303099 https://dev.to/gouthamrayaprolu/why-project-valhalla-will-revolutionize-java-performance-in-2026-3ea6https://horstmann.com/presentations/2025/jcon-valhalla/- Brian Goetz 关于 Valhalla 的技术演讲
https://mirakl.tech/java-how-to-avoid-the-billion-dollar-mistake-f84a7189d4dd

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » Java 的 Valhalla 项目终于对 null 动手了,JEP 8303099 将终结 NPE 空指针异常