← Backend / Java

24_Java 现代语言特性

Java 21 的 enum、record、sealed 与模式匹配在领域建模中的使用。

Java 现代语言特性

学习目标:理解 enum、record、sealed 和模式匹配如何让后端领域模型更清楚。示例以 Java 21 为基线。

1. 用 enum 限定离散状态

字符串状态容易拼错;enum 让合法状态在编译期可枚举,但数据库或外部 JSON 的字符串仍要在边界解析。不要把枚举的 ordinal() 存进数据库:插入新值后序号会变化。存稳定的业务代码更安全。

enum NoteStatus { DRAFT, PUBLISHED, ARCHIVED }

class NoteRules {
    static boolean canEdit(NoteStatus status) {
        return status == NoteStatus.DRAFT;
    }
}

如果将来新增 REVIEWING,检查所有 switch 和权限规则,避免默认分支无声接受新状态。

2. record 是简洁的数据载体

record 自动生成构造器、访问器、equals、hashCode 和 toString,适合不可变的简单值对象或 DTO。

record NoteId(long value) {
    NoteId {
        if (value <= 0) throw new IllegalArgumentException("id must be positive");
    }
}

record 的字段引用不能重新赋值,但若字段是可变列表,对象仍可能通过列表内容变化;需要防御性复制。JPA 实体往往需要不同的构造和生命周期约束,不要机械地全部改成 record。

3. sealed 建模有限分支

当业务结果只有成功与失败等固定类型时,sealed interface 限制直接实现者。Java 21 的模式匹配 switch 可清楚处理各分支:

sealed interface SaveResult permits Saved, Conflict {}
record Saved(long id) implements SaveResult {}
record Conflict(long currentVersion) implements SaveResult {}

class ResultText {
    static String describe(SaveResult result) {
        return switch (result) {
            case Saved saved -> "已保存:" + saved.id();
            case Conflict conflict -> "版本冲突:" + conflict.currentVersion();
        };
    }
}

新增第三种结果时,编译器能提示未覆盖的 switch。但不要为只有两个简单布尔值的场景强行建立复杂层次;领域概念清晰比追求新语法重要。

4. 练习与参考

把笔记状态 DRAFT → PUBLISHED → ARCHIVED 写成状态转换函数,禁止从 ARCHIVED 直接回 DRAFT;为每个合法和非法转换写测试。