Java现代语法特性
Java 在 8 之后持续演进,加入了很多提升表达力和安全性的语法。学习现代语法的目标不是追新,而是知道它们解决什么问题、适合放在哪里、团队项目能否使用。
# 1. var
var 用于局部变量类型推断。
var names = new ArrayList<String>();
var count = 10;
限制:
- 只能用于局部变量。
- 必须能从右侧推断类型。
- 不能用于字段、方法参数、返回值。
适合类型明显的场景:
var userMap = new HashMap<Long, User>();
不适合让代码难读:
var result = service.process(input);
如果右侧无法表达类型语义,显式类型更好。
# 2. 文本块
文本块用于多行字符串。
String sql = """
SELECT id, name
FROM user
WHERE status = 'ACTIVE'
""";
适合:
- SQL。
- JSON 示例。
- HTML 片段。
- 测试数据。
注意缩进和末尾换行会影响实际字符串。
# 3. switch 表达式
传统 switch 容易漏写 break。
String text = switch (status) {
case CREATED -> "待支付";
case PAID -> "已支付";
case CANCELED -> "已取消";
default -> "未知";
};
优势:
- 可以作为表达式返回值。
- 箭头写法避免默认 fall-through。
- 分支更清晰。
# 4. instanceof 模式匹配
旧写法:
if (obj instanceof String) {
String text = (String) obj;
System.out.println(text.length());
}
新写法:
if (obj instanceof String text) {
System.out.println(text.length());
}
减少强转样板代码,也降低强转错误风险。
# 5. record
record 用于定义透明的数据载体。
public record UserDTO(Long id, String name) {
}
自动生成:
- 构造器。
- 访问器。
equals。hashCode。toString。
适合:
- DTO。
- 查询结果。
- 不可变值对象。
- 方法返回组合值。
不适合:
- 复杂领域对象。
- 需要大量可变状态的实体。
- ORM 强依赖无参构造和 setter 的场景。
# 6. sealed class
密封类限制继承范围。
public sealed interface PaymentResult
permits Success, Failed {
}
public record Success(String tradeNo) implements PaymentResult {
}
public record Failed(String reason) implements PaymentResult {
}
适合表达有限类型层次:
PaymentResult
├─ Success
└─ Failed
配合 switch 可以让编译器帮助检查分支覆盖。
# 7. Sequenced Collections
较新的 Java 版本中集合体系补充了顺序集合接口,用于统一“第一个/最后一个”等操作。
核心意义:
- 让有顺序的集合表达更统一。
- 减少不同集合类之间 API 不一致。
- 对
List、Deque、LinkedHashSet、SortedSet等顺序语义更友好。
实际项目是否可用取决于运行 JDK 版本。
# 8. 使用现代语法的原则
- 先确认项目 JDK 版本。
- 团队能理解再使用。
- 语法应提升可读性,而不是炫技。
- DTO 可考虑 record,领域对象谨慎。
- switch 表达式适合枚举和有限状态。
- var 只在类型明显时使用。
- sealed 适合稳定封闭的类型体系。
# 9. 版本意识
不同项目可能运行在 Java 8、11、17、21 或更高版本。写文档和代码时必须说明特性可用版本,避免把高版本语法写进低版本项目。
Java 8:Lambda、Stream、Optional、java.time
Java 10:var
Java 15:文本块正式
Java 16:record 正式
Java 17:sealed class 正式
Java 21:虚拟线程、记录模式等现代能力
# 10. 现代语法落地策略
现代语法的价值是减少样板、提升类型安全和表达业务意图,但它必须服务可维护性。
| 特性 | 最适合 | 谨慎使用 |
|---|---|---|
var | 右侧类型非常明确 | 业务方法返回值语义不清 |
| 文本块 | SQL、JSON、测试数据 | 对缩进和末尾换行敏感的协议 |
| switch 表达式 | 枚举、有限状态映射 | 分支里塞复杂业务 |
| 模式匹配 | 类型判断后立即使用 | 类型分支过多说明模型可能有问题 |
| record | DTO、值对象、查询投影 | JPA 实体、复杂领域对象 |
| sealed | 封闭类型层次 | 需要第三方自由扩展的接口 |
现代 Java 代码可以这样组织:
record 表达数据
│
├─ sealed 表达有限类型
│
├─ switch 表达式做分支映射
│
└─ 模式匹配减少强转
例如支付结果这种封闭模型:
sealed interface PayResult permits PaySuccess, PayFailed {
}
record PaySuccess(String tradeNo) implements PayResult {
}
record PayFailed(String code, String message) implements PayResult {
}
这种建模比使用字符串状态码更不容易漏分支,也更适合重构。团队升级 JDK 时,可以先在 DTO、测试、内部工具代码中使用现代语法,再逐步进入核心领域模型。
# Tips 快问快答
Q:现代语法是不是越新越应该用? A:不是,要看项目 JDK、团队熟悉度和可读性。
Q:var 会让 Java 变成动态类型吗? A:不会,仍然是静态类型,只是局部变量类型由编译器推断。
Q:record 适合替代所有类吗? A:不适合,record 更适合不可变数据载体。
Q:switch 表达式最大好处是什么? A:能返回值,并减少漏写 break 的风险。
Q:sealed class 解决什么问题? A:限制继承范围,表达封闭类型体系。
Q:文本块适合什么? A:多行 SQL、JSON、HTML、测试数据。
Q:instanceof 模式匹配解决什么? A:减少重复强转代码。
Q:使用高版本语法前最先确认什么? A:项目编译和运行使用的 JDK 版本。