JDK17-21特性Pattern-Matching详解
Pattern Matching 详解
一、知识概述
Pattern Matching(模式匹配)是 Java 引入的一系列语言特性,用于简化类型检查和数据提取。从 Java 16 开始逐步引入,到 Java 21 已成为成熟的特性。
1.1 演进历程
| 版本 | 特性 |
|---|---|
| Java 16 | instanceof 模式匹配(正式版) |
| Java 17 | Switch 模式匹配(预览) |
| Java 18 | Switch 模式匹配增强(预览) |
| Java 19 | Record 模式匹配(预览) |
| Java 20 | Record 模式匹配增强(预览) |
| Java 21 | Switch 模式匹配、Record 模式匹配(正式版) |
1.2 解决的问题
传统 Java 需要大量的instanceof检查和类型转换:
// 传统写法:冗长且容易出错Objectobj=getValue();if(objinstanceofString){Stringstr=(String)obj;System.out.println(str.length());}// 使用模式匹配:简洁明了if(objinstanceofStringstr){System.out.println(str.length());}二、知识点详细讲解
2.1 instanceof 模式匹配
2.1.1 基本用法
publicclassInstanceofPatternMatching{publicstaticvoidmain(String[]args){// 基本模式匹配Objectobj="Hello, Pattern Matching!";// 旧写法if(objinstanceofString){Strings=(String)obj;System.out.println("Old way: "+s.length());}// 新写法:类型模式和变量绑定if(objinstanceofStrings){System.out.println("New way: "+s.length());}// 模式变量作用域if(objinstanceofStrings&&s.length()>5){System.out.println("Long string: "+s.substring(0,5));}// 不能在 false 分支使用(编译错误)// if (!(obj instanceof String s)) {// System.out.println(s); // 编译错误// }}}2.1.2 流式作用域
publicclassFlowScoping{publicstaticvoidmain(String[]args){Objectobj=Math.random()>0.5?"Hello":42;// 模式变量仅在"肯定会匹配"的分支可见if(objinstanceofStrings){System.out.println("是字符串: "+s);// s 在此作用域内可用}// s 在此不可用// 结合条件表达式if(objinstanceofStrings&&s.length()>3){// 只有两个条件都满足才进入System.out.println("长字符串: "+s);}// 使用 || 时的注意事项if(objinstanceofIntegeri||objinstanceofStrings){// 这里 i 或 s 可能未初始化// 需要再次检查才能使用if(objinstanceofIntegernum){System.out.println("整数: "+num);}elseif(objinstanceofStringstr){System.out.println("字符串: "+str);}}}// 方法的流式作用域staticStringprocess(Objectobj){// 编译器能推断变量是否已初始化if(!(objinstanceofStrings)){return"Not a string";}// s 在此可用,因为上面如果不是字符串已返回returns.toUpperCase();}}2.2 Switch 模式匹配
2.2.1 基本语法
publicclassSwitchPatternMatching{publicstaticvoidmain(String[]args){Object[]values={"hello",42,3.14,true,newint[]{1,2,3}};for(Objectvalue:values){Stringresult=formatValue(value);System.out.println(result);}}// 传统 switch 不支持类型判断staticStringformatValueOld(Objectobj){if(objinstanceofIntegeri){return"Integer: "+i;}elseif(objinstanceofStrings){return"String: "+s;}elseif(objinstanceofDoubled){return"Double: "+d;}else{return"Unknown: "+obj;}}// 使用 switch 模式匹配staticStringformatValue(Objectobj){returnswitch(obj){caseIntegeri->"Integer: "+i;caseStrings->"String: "+s;caseDoubled->"Double: "+d;caseBooleanb->"Boolean: "+b;casenull->"null value";default->"Unknown: "+obj;};}}2.2.2 带守卫的模式匹配
publicclassGuardedPatterns{publicstaticvoidmain(String[]args){Object[]values={"","hello",0,42,-5,100L,3.14};for(Objectvalue:values){System.out.println(categorize(value));}}// 使用 when 子句添加守卫条件staticStringcategorize(Objectobj){returnswitch(obj){caseStrings when s.isEmpty()->"空字符串";caseStrings when s.length()>10->"长字符串: "+s.substring(0,10)+"...";caseStrings->"字符串: "+s;caseIntegeri when i<0->"负整数: "+i;caseIntegeri when i==0->"零";caseIntegeri when i>100->"大整数: "+i;caseIntegeri->"整数: "+i;caseLongl->"长整型: "+l;caseDoubled->"双精度: "+d;default->"其他类型";};}// 实际应用:处理不同类型的消息staticvoidhandleMessage(Objectmessage){switch(message){caseStringtext when text.startsWith("ERROR:")->System.out.println("错误消息: "+text);caseStringtext when text.startsWith("WARN:")->System.out.println("警告消息: "+text);caseStringtext->System.out.println("普通消息: "+text);caseIntegercode when code>=400&&code<500->System.out.println("客户端错误: "+code);caseIntegercode when code>=500->System.out.println("服务器错误: "+code);caseIntegercode->System.out.println("状态码: "+code);casenull->System.out.println("空消息");default->System.out.println("未知消息类型");}}}2.2.3 匹配顺序的重要性
publicclassPatternOrder{publicstaticvoidmain(String[]args){CharSequencecs="Hello";System.out.println(analyze(cs));// 输出: String: Hello}// 模式匹配按顺序匹配,更具体的类型应放在前面staticStringanalyze(Objectobj){returnswitch(obj){// ❌ 错误顺序:CharSequence 包含 String,永远不会匹配到 String// case CharSequence cs -> "CharSequence: " + cs;// case String s -> "String: " + s; // 永远不会执行// ✅ 正确顺序:更具体的类型在前caseStrings->"String: "+s;caseCharSequencecs->"CharSequence: "+cs;caseIntegeri->"Integer: "+i;caseNumbern->"Number: "+n;