java 17起引入、jdk 21正式落地的switch模式匹配支持枚举类型匹配、变量绑定、守卫条件和结构解构,结合密封类可模拟代数数据类型,提升类型安全与表达力。

Java 17 起逐步引入、JDK 21 正式落地的 Switch 模式匹配(Pattern Matching for switch),让 switch 不再只是“值匹配”,而是能结合类型、守卫条件与结构解构,实现对枚举的多态语义提取——尤其当枚举携带行为、元数据或封装状态上下文时,这种能力尤为关键。
用模式匹配直接解构枚举携带的数据
传统 switch 只能跳转到 case 标签,而新模式允许你在匹配的同时绑定变量、提取字段。前提是枚举定义中已封装结构化信息:
例如订单状态枚举带错误码和提示语:
public enum OrderResult {SUCCESS("OK", 0),
RETRY_LATER("服务暂不可用", 503),
INVALID_PARAM("参数错误", 400);
private final String message;
private final int code;
OrderResult(String message, int code) {
this.message = message;
this.code = code;
}
public String message() { return message; }
public int code() { return code; }
}
配合 switch 表达式 + 模式匹配,可直接解构并使用字段:
String response = switch (result) {case SUCCESS s -> "成功:" + s.message();
case RETRY_LATER r when r.code() >= 500 -> "请稍后重试(" + r.code() + ")";
case INVALID_PARAM i -> "校验失败:" + i.message() + "(" + i.code() + ")";
default -> throw new IllegalStateException("未预期结果:" + result);
};
这里每个 case SUCCESS s 不仅匹配类型,还把当前枚举实例绑定为变量 s,后续可直接调用其方法,无需重复写 result.message()。
结合守卫条件(when)做业务级分支细化
同一个枚举值在不同业务上下文中可能需差异化处理。守卫条件让 switch 支持“值 + 上下文”双重判断:
- 比如
PENDING状态,在“支付超时检查”场景下需关注创建时间,在“人工审核队列”中则要看是否标记为加急 - 可写作:
case PENDING p when isOverdue(p.createdAt()) -> handleTimeout(p); - 或:
case PENDING p when p.isUrgent() -> escalateToManager(p);
守卫表达式在运行时求值,但编译器仍确保所有枚举常量被显式覆盖——既保留穷尽性检查,又支持动态逻辑分流。
与密封类协同,模拟代数数据类型(ADT)语义
纯枚举适合“状态集合”,但若需表达“多种异构结果”(如成功含数据、失败含异常、进行中含进度),更推荐用 密封枚举(sealed enum) 或 密封接口 + 枚举实现类:
public sealed interface PaymentResultpermits PaymentSuccess, PaymentFailed, PaymentPending { }
record PaymentSuccess(String txId, BigDecimal amount) implements PaymentResult { }
record PaymentFailed(String reason, Throwable cause) implements PaymentResult { }
enum PaymentPending implements PaymentResult { IN_PROGRESS, AWAITING_CONFIRMATION }
此时 switch 模式匹配可同时处理具体 record 和枚举子类:
switch (result) {case PaymentSuccess(var id, var amt) -> log("交易完成:" + id + ", 金额:" + amt);
case PaymentFailed(var reason, var ex) -> alert("失败:" + reason, ex);
case PaymentPending.IN_PROGRESS -> retryIfStuck();
case PaymentPending.AWAITING_CONFIRMATION -> sendReminder();
}
这已接近函数式语言中的代数数据类型匹配,比单层枚举更具表现力,且编译器强制覆盖全部 permits 类型。
避免 fallback 陷阱:用显式 default + 异常代替模糊兜底
即使启用了模式匹配,也不要依赖 default 来掩盖遗漏。正确做法是:
- 所有枚举值都显式列出(哪怕当前逻辑为空),增强可维护性
- 确有预留/废弃状态,用
case RESERVED: /* intentionally ignored */ break; - default 分支只用于真正未知的运行时异常情况,并抛出带上下文的
IllegalStateException
这样既满足编译期穷尽性要求,又让未来新增枚举值时,编译器立刻报错提醒补充分支逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











