当前位置:首页 > 文章列表 > 文章 > java教程 > JDK 26 基本类型模式怎样影响模式匹配

JDK 26 基本类型模式怎样影响模式匹配

来源:17golang原创 2026-10-21 11:35:50 0浏览 收藏

如果一段 Java 代码要同时判断 Integer、Long 和 null,旧写法往往要先判断引用类型,再手动拆箱,最后补上范围和空值处理。JDK 26 的 JEP 530(第四次预览)把基本类型带入更多模式匹配场景:可以在 instanceof 中测试基本类型,也可以在 switch 和 record pattern 中使用基本类型。它减少的是分支样板,不是所有转换风险。

官方地址:https://docs.oracle.com/en/java/javase/26/language/primitive-types-patterns-instanceof-switch.html

迁移时先把输入的静态类型、运行时包装类型和可能的 null 分开看。primitive pattern 只有在测试转换安全时才匹配;预览语法也不会把 null 变成一个可以自动拆箱的数值。

先看基线:旧代码为什么需要多层判断

假设路由层收到的是 Object,业务要把整数型配置分成“普通整数”和“较大整数”。在 JDK 25 及以前,instanceof 的右侧只能写引用类型,代码需要先识别包装类,再显式取值:

static String classify(Object input) {
    if (input instanceof Integer integer) {
        // 先匹配包装类型,再读取已经完成拆箱的 int 值。
        return integer >= 0 ? "non-negative-int" : "negative-int";
    }
    if (input instanceof Long value) {
        // Long 与 Integer 是两种不同的包装类型,不能合并成一个 primitive 分支。
        return value > Integer.MAX_VALUE ? "large-long" : "small-long";
    }
    // null 和其它对象都落到这里,业务还要决定是否分别处理。
    return "other";
}

这段基线的分支数量不是性能基准,而是迁移时可观察的维护基线:两个包装类型判断、一个兜底分支,以及每个分支中不同的转换语义。若再加入 Short、Float 或记录组件,重复会继续增加。

基本类型 pattern 改变了哪一层语法

JDK 26 预览语法允许在模式位置写基本类型。下面的例子展示“值能否安全转换成 int”这一判断;它不是把任意对象强行转换成 int。为了尝试预览特性,编译和运行都需要使用 JDK 26 与 --enable-preview:

static String asInt(Object input) {
    if (input instanceof int value) {
        // 只有测试转换精确且可安全完成时,value 才会进入分支。
        return "int=" + value;
    }
    if (input instanceof long value) {
        // long 也可以作为目标模式,但超出 int 的值不会凭空变成 int。
        return "long=" + value;
    }
    return "not-an-integer-pattern";
}

// 编译:javac --release 26 --enable-preview PatternDemo.java
// 运行:java --enable-preview PatternDemo

这里最容易误读的是“范围更大”不等于“转换一定安全”。一个 int 值可以转换为某些 long 值而不丢失信息,但转换到 float 时还要考虑有效精度;测试转换会阻止不精确的匹配。JDK 26 的语言说明把这类规则归入安全转换,而不是简单套用普通强制转换。

JDK 26 模式匹配上下文中基本类型、包装类型和模式变量的静态关系
图1:这是模式匹配上下文的静态说明图,展示 primitive pattern、包装类型、模式变量和安全转换的关系,不是截图或运行证据。

switch 中要分清 selector、case 常量和 pattern

switch 的变化更适合用“输入类型—匹配形式—结果”来理解。JDK 26 允许更多基本类型作为 selector,并允许用基本类型 pattern 描述值的类型,再用 when 缩小范围:

static String bucket(Object input) {
    return switch (input) {
        case int value when value  {
            // when 只限制已经匹配到的 int 值,不负责把 Object 变成 int。
            yield "negative-int";
        }
        case int value -> {
            // 同一类型的无守卫 pattern 要放在更具体的 guarded pattern 之后。
            yield "non-negative-int";
        }
        case long value -> "long=" + value;
        case null -> "null";
        default -> "other";
    };
}

上面的顺序表达了一个编译期边界:带 when 的分支先处理,未加守卫的 case int value 不能放在它前面,否则前面的无守卫 pattern 会把后者覆盖。default 也不等于“自动接住 null”;要把 null 作为输入状态处理,就明确写 case null。

如果 selector 本身就是 long、float、double 或 boolean,case 常量必须遵守对应的常量类型规则;不能因为 int 可以拓宽到 double,就把任意整数文字混在 double selector 的 case 中。case 常量的可赋值关系,与 case pattern 的测试转换关系不是同一套规则。

装箱边界:Object、包装类和 null 不是一回事

JEP 530 的价值之一,是允许程序对“值被放进 Object 后又想按数值类型判断”的场景写得更直接;但运行时对象依然可能是 Integer、Long 或其它包装实例。模式匹配不会把一个 Long 里超出范围的值安全地变成 int。

static String inspect(Object input) {
    return switch (input) {
        case int value -> "matched-int=" + value;
        case long value -> "matched-long=" + value;
        case Integer boxed -> {
            // 这个分支与前面的 int pattern 讨论的是不同视角,实际代码应避免重叠设计。
            yield "boxed-integer=" + boxed;
        }
        case null -> "missing";
        default -> "unsupported";
    };
}

实际迁移时不要机械地把所有包装类分支和 primitive pattern 同时保留。先决定 API 想表达的是“运行时对象属于哪个包装类”,还是“值能否安全地按某个 primitive 解释”。前者更接近类型分类,后者更接近数值转换测试;二者混排会让后续维护者误判分支是否互斥。

Object 到包装值、基本类型模式、安全转换和 null 分支的静态边界
图2:这是装箱与安全转换的静态关系图,重点看 Object、包装值、primitive pattern 和 null 的边界,不代表实际执行轨迹。

record pattern 里,基本类型组件也要看转换方向

如果 record 的组件是数值类型,primitive pattern 可以出现在解构位置。重点仍然是组件的静态类型和目标 pattern 是否允许安全测试转换,而不是“record 一拆开就可以随意缩窄”。

record Reading(long value, String unit) {}

static String format(Object input) {
    return switch (input) {
        case Reading(int value, String unit) when value >= 0 -> {
            // 这里要求 long 组件到 int pattern 的匹配边界是安全的。
            yield value + " " + unit;
        }
        case Reading(long value, String unit) -> {
            // 兜底分支保留原始 long 语义,避免把大值截断。
            yield value + " " + unit;
        }
        default -> "not-a-reading";
    };
}

这个例子同时说明了一个设计选择:需要小范围计算时,可以用更窄的 primitive pattern;需要保持原始数据时,则保留 long。若业务允许截断,应在普通代码中显式说明并测试,不要把 pattern 的“匹配成功”误解成强制转换的许可。

用三组指标判断迁移是否值得

本特性主要减少的是模式匹配的样板和转换分支,因此迁移评估应该记录可维护性指标,而不是只看字节码或一次微基准。可以选一段真实分支做前后对照:

观察项旧写法基线迁移后重点
分支数量包装类判断、显式取值、null 兜底分别出现pattern 与 when 是否让每个业务状态只出现一次
转换点手写拆箱、强转或范围判断较分散安全测试转换是否集中在 pattern 边界
回归样本常规值覆盖较多,极值与 null 容易遗漏补齐包装类型、越界值、负值、浮点精度和 null

如果代码只是把几个 if 换成更短的 switch,但没有减少歧义,迁移收益可能不大。反过来,对接收异构配置、事件或记录的边界层,primitive pattern 能把“识别类型”和“安全取值”放在同一个结构里,通常更容易审阅。

上线前先守住这几个边界

  • 把 JEP 530 当作预览特性,编译和运行环境都明确使用 JDK 26 与 --enable-preview,不要把它当成已经永久定型的语法。
  • 分别准备 Integer、Long、极小值、极大值、负值、浮点近似值和 null 的输入样本。
  • 检查 guarded pattern 与无守卫 pattern 的顺序,避免 dominance 规则让代码无法编译或让意图不清楚。
  • 在 API 边界明确“按包装类分类”还是“按安全数值转换匹配”,不要同时写出互相覆盖的分支。
  • 需要保留原始数值时使用宽类型 pattern;需要缩窄时把精度、范围和失败分支写进测试名称。

归纳起来,JDK 26 的基本类型模式让模式匹配从“引用类型识别”向“值与类型一起判断”扩展。真正的迁移动作不是把 instanceof Integer 全部替换成 instanceof int,而是先确认安全转换、装箱状态、null 处理和 switch 覆盖范围,再选择更短但仍然可读的表达。

两个常见疑问

基本类型 pattern 会自动处理 null 吗? 不会。输入为 null 时,primitive pattern 不会提供一个可用数值;在 switch 中需要用 case null 明确表达,或在外围先定义空值策略。

启用预览后,所有旧 switch 都要改写吗? 不需要。预览能力是新增表达方式,已有代码可以继续按原语义工作。只有当原代码确实被包装类型分支、手动拆箱和范围判断拖长,且团队能够统一 JDK 26 预览运行条件时,才值得按边界逐段迁移。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
PHP 8.5 unserialize 相关魔术方法怎样迁移PHP 8.5 unserialize 相关魔术方法怎样迁移
上一篇
PHP 8.5 unserialize 相关魔术方法怎样迁移
JDK 26 HTTP/3 客户端怎样评估迁移影响
下一篇
JDK 26 HTTP/3 客户端怎样评估迁移影响
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    575次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    618次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    649次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    610次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    426次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码