登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

Java switch pattern matching 的 null 分支处理

来源:17golang原创

时间:2026-11-01 06:23:50 364浏览 收藏

Java 21 的 switch pattern matching 可以直接按类型分支,但 null 仍然是一个单独的匹配边界:case Object value 不会自动接住空引用。selector 为 null 且没有 case null 时,switch 会抛出 NullPointerException;要处理它,必须显式写出 case null,或者在确实共享兜底策略时使用 case null, default。

官方文档:https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html

判断口诀:类型模式只负责非 null 对象;null 要单独声明。独立业务写 case null,与未知值共用策略才写 case null, default,并把合并标签放在最后。

本文要点

  • 类型模式不会匹配 null,缺少 null 标签时会抛 NPE。
  • case null 可以与类型模式分开表达空值策略。
  • case null, default 只能与 default 合并,且应位于 switch 末尾。

先看清 null 为什么不会命中类型模式

最容易误判的写法是把 Object 当成“所有输入”,然后省略 null 分支。pattern switch 的运行规则会先区分 null 引用;只有非 null 值才继续尝试类型模式。因此下面的 case Object value 能覆盖普通对象,却不能替代 case null。

static String describe(Object value) {
    return switch (value) {
        // 类型模式只接收非 null 的 Object
        case Object object -> "对象:" + object.getClass().getSimpleName();
        // 没有 case null 时,value 为 null 会在匹配前抛出 NPE
    };
}

这不是 default 是否穷举的问题,而是 null 在模式匹配前就有专门的处理规则。只要 selector 可能为空,就应在设计阶段明确空值是业务状态、缺省值,还是应该直接暴露为异常。

Java switch pattern matching 中 selector、null 标签和类型模式的静态关系说明图
图1:null 分派结构说明图,查看 selector、null 标签与类型模式的边界关系。

需要独立策略时显式写 case null

如果空值代表“未提供”“尚未加载”或“需要单独提示”,就把它写成独立标签。这样既能保留类型模式的变量,也不会把 null 伪装成一个普通对象。

static String normalize(Object value) {
    return switch (value) {
        // 空引用是独立业务状态,不访问任何模式变量
        case null -> "未提供";
        // 只有匹配 String 后,text 才在当前分支内可用
        case String text -> "文本:" + text.trim();
        // 其他非 null 类型走默认处理
        default -> "其他类型:" + value.getClass().getSimpleName();
    };
}

这里的顺序也表达了阅读意图:先处理空引用,再处理有明确业务含义的类型,最后由 default 接住剩余非 null 值。case null 不能和 case String text 放在同一个标签里,因为类型模式需要一个可用的非 null 模式变量。

什么时候用 case null, default

当 null 和其他未识别对象确实共享同一套兜底行为时,可以把两个标签合并。它适合“只要不是受支持的 String 就返回通用提示”这类场景,但要注意合并后无法区分到底是 null 还是其他类型。

static String category(Object value) {
    return switch (value) {
        // 先保留明确的类型分支
        case String text -> "文本:" + text;
        // null 与未知非 null 对象共享兜底结果
        case null, default -> "未分类";
    };
}

case null, default 是合法的合并标签,但它不能再与后续标签混用,应放在最后。若后续还想区分数字、日期等类型,应改回独立的 case null 加具体类型模式,再用单独的 default 收尾。

Java case null、类型模式与 null/default 合并写法的静态关系说明图
图2:分支选择说明图,对比独立 null 策略与合并兜底策略的适用边界。

编译前按四个边界检查

检查项正确判断常见误区
类型模式只匹配非 null 对象把 Object 模式当成 null 兜底
空值策略独立写 case null试图写 case null, String s
合并兜底case null, default 放在末尾后面继续添加 case
模式变量只在匹配成功的分支使用在 null/default 分支引用 String 变量

如果 switch 需要返回结果,增强型 switch 表达式或带模式的 switch 语句还必须满足穷举要求。最小可行的工程决策是先列出 null、已知类型和未知类型三类输入,再决定是分别记录、统一兜底,还是让异常尽早暴露。

常见问题

有了 default,为什么 null 仍然抛 NPE?

default 只处理非 null 值中没有命中其他标签的情况。null 要由 case null 或 case null, default 明确覆盖。

case null, default 能放在中间吗?

不能把它当作普通中间分支继续往下写;该合并标签相当于最终兜底,应位于 switch 的末尾。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>