JDK27升后原始类型pattern怎么写

升到 JDK 27,instanceof/switch 可写原始类型 pattern(JEP532 第五预览);按 exact 转换匹配,仍须 --enable-preview。

同系列:PEM 编解码、TLS 后量子混合、LazyConstant、结构化并发------一句对照,不写进本稿交付。

痛点:原始类型还得先强转,再猜会不会丢精度?

现场三类卡点:

  1. instanceof 过去不能测原始类型 ------int 能否安全落进 byte,只能自己比范围或强转后再比对;写错就静默截断,线上要靠单测或日志才发现。
  2. switch 选不了 long / float / double / boolean------浮点分支只好拆成 if-else;布尔穷尽也写不成 switch,评审时常被问「为什么不用模式匹配」。
  3. 嵌套 record 里 double 想当 int 用 ------旧写法必须 JsonNumber(double a) 再手动 (int)a,窄化是否丢信息全靠人眼,和「先 instanceof 再强转」是同一类负担。

目标很具体:在 JDK 27 preview 上,用原始类型 pattern / instanceof / switch,按 exact conversion 写通匹配与绑定;并记住 float case 常量必须写成 0f。

图注:值进入 exact 转换判定------能无损落到目标类型则匹配并绑定,否则走下一分支;编译与运行都要带 --enable-preview。

JDK 27 交付了什么?JEP 532 第五预览

口径以 JEP 532、JDK 27 项目页、Oracle JDK 27 Release Notes · Language 为准(核对日 2026-10-24 Asia/Shanghai):

项 口径
状态 Closed / Delivered ,Release = 27
轮次 Fifth Preview(标题:Primitive Types in Patterns, instanceof, and switch)
相对 JEP 530 without change(530 已收紧 unconditional exactness 与 switch dominance;532 无再改语义)
GA JDK 27 于 2026-09-15 达 General Availability
开关 javac --release 27 --enable-preview 与 java --enable-preview
勿写 「已转正 / 无需 preview」------官方仍标 preview language feature

历史一句:JEP 455(JDK 23)提出,488(24)、507(25)无改再预览,530(26)做了两处收紧后,532 第五次预览且相对 530 无变更。Closed/Delivered 只表示该 JEP 随 27 进了发行版;交付物本身仍是预览语言特性------javac 开了、java 没开,或反过来,都会一边过、一边挂。

JLS preview 文档(可到达)Changelog 写明:2026-05-04 为 Java SE 27 第五预览刷新,无规范性变更。创作优先引 JEP 例句,JLS 作边界复核即可。

bash 复制代码
# 编译(两边都要带 --enable-preview)
javac --release 27 --enable-preview PrimitivePatternDemo.java

# 运行
java --enable-preview PrimitivePatternDemo

# 或源码启动 / jshell
java --enable-preview PrimitivePatternDemo.java
jshell --enable-preview

团队规范若禁止 preview,本稿只能当调研与 PoC 清单,不能当「升完 27 就全仓替换手写范围判断」的通行证。

instanceof:只测 vs 测并绑定

右侧是 Type (非 Pattern)时,只做安全转换前置检查,不自动转换,仍要传统 cast:

java 复制代码
// 需 --enable-preview(javac --release 27 --enable-preview / java --enable-preview)
public class InstanceofTypeTest {
    public static void main(String[] args) {
        int i = 42;
        if (i instanceof byte) {   // 值能无损落进 byte
            byte b = (byte) i;     // 仍须传统强转
            System.out.println(b);
        }
    }
}

右侧写成 pattern (instanceof T t)时:测试 + 条件转换,成功则绑定:

java 复制代码
// 需 --enable-preview
public class InstanceofPatternBind {
    public static void main(String[] args) {
        int i = 42;
        if (i instanceof byte b) {
            System.out.println(b);  // 已绑定,无需再 (byte)i
        }
    }
}

语义就是 JEP 原话方向:「test if i instanceof byte and, if so, cast i to byte and bind that value to b」 。没有新增「另一种转换种类」------Non-Goals 写明 not a goal to add new kinds of conversions ;依据仍是 exact conversion (无信息损失则报告 true)。

实务上优先写 pattern 绑定:少一次手写 cast,也少一次「测过了却忘了转」的疏漏。若只想做守卫、后面仍要走旧强转路径,再单独用类型测试形态。

exact 转换:42 能进 byte,1000 不能

运行时用 exact conversion 判定。JEP 例句(可本地改数字复验):

java 复制代码
// 需 --enable-preview
public class ExactConversionDemo {
    public static void main(String[] args) {
        int a = 42;
        System.out.println(a instanceof byte);   // true(exact)

        int b = 1000;
        System.out.println(b instanceof byte);   // false(not exact)

        int c = 16_777_217;                      // 2^24 + 1
        System.out.println(c instanceof float);  // false(not exact)
        System.out.println(c instanceof double); // true(unconditionally exact)
    }
}
左侧值 右侧类型 结果 原因(口径)
42 byte true exact,无损
1000 byte false 超出 byte 范围,not exact
2^24+1 float false float 尾数装不下,not exact
2^24+1 double true unconditionally exact

2^24+1 这组最容易误判:人直觉觉得「int 比 float 窄,应该总能进 float」,但 float 有效位数约 24 bit,超过就会丢精度,因此 not exact ;进 double 则 unconditionally exact。写作时把「instanceof byte 只测」和「instanceof byte b 测并绑定」分开讲,避免读者以为类型测试形态已经把变量变成了 byte。

switch:long / float / double / boolean

JEP 把 switch 选择器扩到剩余原始类型:long、float、double、boolean(及对应装箱类型)。硬约束:case 常量类型必须与选择器相同 (或对应装箱)。选择器是 float / Float 时,常量必须是 float 字面量------下面这段合法,但若把 0f 误写成 0 会非法:

java 复制代码
// 需 --enable-preview
public class SwitchFloatDemo {
    static float classify(float v) {
        return switch (v) {
            case 0f -> 5f;
            case float x when x == 1f -> 6f + x;
            case float x -> 7f + x;
        };
    }

    public static void main(String[] args) {
        System.out.println(classify(0f));
        System.out.println(classify(1f));
        System.out.println(classify(2.5f));
    }
}

浮点 case 按 representation equivalence 判重;表示等价的两个字面量会撞成重复 label(例如 1.0f 与 0.999999999f)。写字面量时别「近似相等就当同一个 case」------编译器按表示等价,不是按十进制肉眼。

boolean 列全 true / false 即穷尽,再加 default 非法:

java 复制代码
// 需 --enable-preview:boolean 穷尽示例
public class SwitchBooleanDemo {
    static String label(boolean ok) {
        return switch (ok) {
            case true -> "yes";
            case false -> "no";
            // 不可再加 default:已穷尽
        };
    }

    public static void main(String[] args) {
        System.out.println(label(true));
        System.out.println(label(false));
    }
}

long 选择器同理,case 常量用 long 字面量(带 L)或可判定为同类型的常量;别把 int 字面量随手塞进 switch (long) 的 case 里指望隐式放宽------规则要求类型对齐。

图注:switch 选择器扩至 long/float/double/boolean;float 分支常量必须 0f 而非 0,类型与选择器对齐。

嵌套 record:JsonNumber(int a) 何时匹配?

旧写法嵌套原始类型 pattern 须与组件类型完全一致 (JsonNumber(double a)),再手动 (int)a。JEP 允许在组件是 double 时直接写 int a------当且仅当 该 double 能无损转为 int 才匹配:

java 复制代码
// 需 --enable-preview
sealed interface JsonValue permits JsonObject, JsonString, JsonNumber {}

record JsonObject(java.util.Map<String, JsonValue> map) implements JsonValue {}
record JsonString(String s) implements JsonValue {}
record JsonNumber(double d) implements JsonValue {}

public class JsonAgePattern {
    static void printAge(JsonValue json) {
        if (json instanceof JsonObject(var map)
                && map.get("name") instanceof JsonString(String n)
                && map.get("age") instanceof JsonNumber(int a)) {
            System.out.println(n + " age=" + a);
        } else {
            System.out.println("no exact int age");
        }
    }

    public static void main(String[] args) {
        var ok = new JsonObject(java.util.Map.of(
                "name", new JsonString("Ada"),
                "age", new JsonNumber(30.0)));
        var bad = new JsonObject(java.util.Map.of(
                "name", new JsonString("Bob"),
                "age", new JsonNumber(30.5)));
        printAge(ok);   // Ada age=30
        printAge(bad);  // no exact int age
    }
}

匹配失败分支必须保留------不是「任意嵌套深度总能自动窄化」。JSON 年龄字段若可能带小数,就要在 else 里显式处理,或退回 JsonNumber(double a) 再自行决定舍入策略。

Dominance:一句源不兼容提醒

无条件 pattern 之后的死 case,现在会在编译期报错;这构成对语言的 source-incompatible 变化------以前能编过、但易误导维护者的 switch,升级后可能直接失败。JEP 530 已引入 tighter dominance;532 相对 530 无再改 。边界有限:主要冲击「无条件模式后再写其它 case」以及「常量已被前置类型模式无条件覆盖」的少数 switch,勿写成「升级后 pattern/switch 大面积无法编译」。

典型边界(selector 类型为接口 A 时,case A _ 无条件匹配,其后 case B _ 被 dominate):

java 复制代码
// 需 --enable-preview;演示 dominance,勿当业务模板
interface A {}
interface B {}

public class DominanceDemo {
    static void demo(A a) {
        switch (a) {
            case A _ -> { /* unconditional for selector A */ }
            // case B _ -> { }  // 编译错误:dominated
        }
    }

    public static void main(String[] args) {
        demo(new A() {});
    }
}

实务上:升 27 后若旧 switch 报「dominated」,先删掉无条件 pattern 后面的死分支,而不是关掉 preview 硬扛。多数业务代码没有「无条件 pattern 后再挂一堆 case」这种写法;真正撞上的,按编译器提示收敛即可。

怎么验?

按下面清单自测,比只看 JEP 截图踏实:

  1. 开关成对 :javac --release 27 --enable-preview 与 java --enable-preview 都开;只开一边会一边过、一边挂。
  2. exact 三组 :42 instanceof byte → true;1000 instanceof byte → false;16_777_217 instanceof float → false、instanceof double → true。
  3. float case :switch (float) 里写 case 0 → 应编译失败 ;改 case 0f → 通过。
  4. boolean 穷尽 :true/false 列全后再加 default → 应编译失败。
  5. 嵌套 JsonNumber :30.0 → 匹配 int a;30.5 → 不匹配,走 else。
  6. 别误验:不要把 PEM / TLS / LazyConstant / 结构化并发的 API 拿来证明本稿能力------那些是同发版其它 JEP,见文首内链。

和旧代码怎么并存?

升 27 不必立刻全局替换 if-else。旧「先范围判断再强转」在 preview 关闭的模块里仍是唯一路径;新模块、已开 --enable-preview 的实验仓,可优先用 instanceof byte b 与 float/boolean switch。迁移建议:

  1. 先改测试与校验逻辑里「数值能否无损落进更窄类型」的分支------失败成本低,也方便对照 exact 表。
  2. 再动手写协议解析 / DTO 归一化;生成代码与第三方库未声明 preview 前,保持旧写法。
  3. Code review 清单加两条:float case 是否写成了整数 0;无条件 pattern 后是否还挂着死 case。
  4. CI 若混用多 JDK,把 --enable-preview 收进明确的 preview profile,避免「本机过、流水线挂」。

同发版的 PEM、TLS 混合、LazyConstant、结构化并发已有专文,本稿只守住「原始类型 pattern + exact + switch 扩展」这条线。

常见误读 FAQ

Q:Closed/Delivered 是不是等于可以关 preview?

不是。Closed/Delivered 表示该 JEP 随 JDK 27 交付进发行版;特性仍标 Fifth Preview,官方给出的编译/运行命令都带 --enable-preview。

Q:相对 JDK 26 的 JEP 530,27 又改了什么语义?

without change。530 已增强 unconditional exactness 定义并收紧 switch dominance;532 第五次预览,无再改。

Q:instanceof byte 会不会自动把变量变成 byte?

不会。类型测试形态只报告能否 exact 转换,强转仍要自己写;要绑定请用 instanceof byte b。

Q:float 的 case 0 为什么不行?

选择器是 float 时,case 常量必须是 float 字面量(或对应装箱)。写成 0 是 int 常量,类型不匹配,非法;应写 0f。

Q:嵌套 JsonNumber(int a) 失败是不是编译错误?

不是。匹配失败走运行时下一分支(例如 else);只有当 double→int exact 时才进入绑定。务必保留失败路径。

和装箱类型怎么对齐?

选择器或 instanceof 左侧既可以是原始类型,也可以是对应装箱类型;JEP 明确 switch 覆盖 long/float/double/boolean 以及对应 boxed types。写作时记住两条:

  1. case 常量类型仍要对齐 :Float 选择器上的常量同样必须是 float 字面量(如 0f),写成整数 0 一样非法。
  2. 穷尽规则看 unconditional exactness :包装类型 W(对应原始类型 P)上,若某类型 pattern 对 P unconditionally exact,则可穷尽 W(null 进 remainder)。例如 Byte 上仅 case int p 一类 unconditionally exact 的 pattern 即可穷尽------这是 JEP 摘要口径,主文不必展开成长证明。

日常业务更常碰到的是「原始 int/long 进窄类型」和「float/boolean switch」;装箱路径先保证常量类型与 null 余项想清楚,再谈穷尽表。

完整可编译串联示例

把类型测试、pattern 绑定、float switch 收进一个小类,便于本地 javac --release 27 --enable-preview 后 java --enable-preview:

java 复制代码
// 需 --enable-preview(javac --release 27 --enable-preview / java --enable-preview)
public class PrimitivePatternDemo {
    static String narrow(int i) {
        if (i instanceof byte b) {
            return "byte:" + b;
        }
        return "too-wide:" + i;
    }

    static float classify(float v) {
        return switch (v) {
            case 0f -> 5f;
            case float x when x == 1f -> 6f + x;
            case float x -> 7f + x;
        };
    }

    public static void main(String[] args) {
        System.out.println(narrow(42));    // byte:42
        System.out.println(narrow(1000));  // too-wide:1000
        System.out.println(classify(0f));
        System.out.println(classify(1f));
        int wide = 16_777_217;
        System.out.println(wide instanceof float);   // false
        System.out.println(wide instanceof double);  // true
    }
}

期望:42 走 byte 绑定;1000 走 too-wide;float 0f/1f 分别进对应分支;2^24+1 对 float 为 false、对 double 为 true。任一步不符,先查是否漏了 --enable-preview,再查 case 是否误写成 0。

为什么不该手写范围常量?

旧代码常见:

java 复制代码
if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
    byte b = (byte) i;
    // ...
}

对 byte/short/char 这种「边界清楚」的整数窄化,手写范围大多能对;但一到 int → float、long → double,边界就不再是「最大值最小值」那么简单------尾数位数、次正规数、表示等价都会让「看起来在范围内」的值其实 not exact 。JEP 把判定收进语言:instanceof / pattern 按 exact conversion 说话,比散落各处的魔法常量更不容易写歪。

这也解释了为什么 16_777_217 instanceof float 是 false:不是「int 比 float 小所以一定能转」,而是「转完再转回能否无损」。单测里把 JEP 三组例句钉死,比自己发明一组边界值省心。

预览特性怎么跟生产节奏对齐?

第五预览、相对 530 无变更,意味着语义已连续多轮稳定,但平台仍要求显式开关。常见落地方式:

  • 实验模块 / 原型仓 :pom/build.gradle 里单独 profile 打开 --enable-preview,与主仓隔离。
  • 主仓:继续用手写范围或工具方法;等特性转正(未来 JEP 若 Final)再全局替换------本稿不预测转正版本。
  • 文档:README 写明「本目录示例需 JDK 27 + enable-preview」,避免同事用 25/26 裸跑报奇怪语法错。

评审口径建议统一成:「JEP 532 第五预览,Closed/Delivered for 27,相对 530 without change,必须 enable-preview」------比「JDK27 新语法」六个字清楚。

升级清单(给评审贴一条)

把下面几条贴进 JDK 27 语言预览评审即可,不必另开长文:

  1. 模块/流水线明确声明 --enable-preview,编译与运行成对出现。
  2. 数值窄化优先 instanceof T t,少用手写范围常量;对照 exact 表写单测。
  3. float/double switch:case 字面量带 f/d;禁止「看着像 0 就写 0」。
  4. boolean switch:列全 true/false 后不要再加 default。
  5. 嵌套 record 窄化:保留匹配失败分支;小数年龄等场景勿假设总能进 int。
  6. 编译若报 dominated:删无条件 pattern 后的死 case,视为 530/532 收紧后的预期行为。
  7. 勿把本稿写成 PEM/TLS/LazyConstant/结构化并发的替代交付------那些已有专文内链。

小结

点 结论
改了什么 原始类型进入 pattern / instanceof / switch 全上下文
状态 JEP 532 Fifth Preview;Closed/Delivered for 27;相对 530 without change
instanceof instanceof byte 只测;instanceof byte b 测并绑定
判定 exact conversion;42→byte true,1000→byte false
switch 支持 long/float/double/boolean;float 常量必须 0f
嵌套 JsonNumber(int a) 仅当 double→int exact
开关 --enable-preview(javac --release 27 + java)
勿抢 PEM / TLS PQ / LazyConstant / Structured Concurrency

升到 27 后,原始类型匹配能写进语言正面语法。守住 exact 与 case 常量类型两条红线,并接受仍是第五预览,就能把「先猜再强转」换成可核对的 pattern。本地用 JEP 三组 exact 例句加 float 0f 负例跑一遍,比只改业务分支踏实。其它 JDK 27 能力见前述内链,本文不展开。

相关推荐
ZealSinger13 天前
JDK27升级后紧凑对象头怎么做AB对比
jdk27·紧凑对象头·ab对比·容器rss
AI人工智能+电脑小能手2 个月前
大白话说Java设计模式-45-解释器模式(源码剖析篇)
java·设计模式·解释器模式·源码分析·pattern·spel·javacc
tianyu2342 个月前
Java 正则表达式终极指南:从 Pattern 到 Matcher,从双重转义到性能优化,一篇全搞定
java·开发语言·正则表达式·group·find·pattern·matcher
智慧地球(AI·Earth)3 个月前
MAX-API v1.0.4-preview.4:GPT-5.6 缓存写入计费、跨协议兼容与安全验证升级
preview·max api next·gpt5.6
智慧地球(AI·Earth)4 个月前
重大安全更新:MAX API v1.0.4-preview.2 修复账号归属、quota 溢出与 SSRF 风险
preview·max api next·重大安全更新
ideal-cs5 个月前
总结:生产环境Logback日志配置模板与pattern格式案例
java·log4j·logback·pattern·后端日志
长城20248 个月前
HTML5中表单的pattern属性解析
前端·正则表达式·html·html5·pattern·pattern属性·pattern正则表达式
荣--2 年前
单件模式的困境与替代方案
pattern·单件模式
唐僧洗头爱飘柔95272 年前
【Java基础】正则表达式的使用与常用类分享
java·开发语言·正则表达式·java基础·pattern·java se·java必备技能