JDK17 前后写法对比:差点没认出是 Java!

Java,一直被开发者戏称为"啰嗦",但从 JDK 12 到 JDK 17,这门语言发生了显著变化。多个语法层面的增强让 Java 更加简洁、表达力更强,也更接近现代语言的风格。本文将带你梳理这六个版本中 Java 的关键语法演进。

语法新特性一览

1. switch 表达式:不再"陷阱重重"

痛点

传统 switch 不支持返回值,且 break 的遗漏常导致 bug。

新特性(JEP 325/354/361)

  • switch 可作为表达式返回值
  • 引入箭头语法(->
  • 支持多标签匹配
  • 使用 yield 显式返回值

示例

对 HTTP 状态码进行分类处理,例如:构建统一响应消息或记录错误日志。

rust 复制代码
String result = switch (statusCode) {  
    case200 -> "OK";  
    case404 -> "Not Found";  
    case500 -> {  
        logError();  
        yield "Server Error";  
    }  
    default -> "Unknown";  
};

优势:简洁、安全、不易出错,便于表达逻辑分支。

2. 文本块(Text Blocks):三引号带来的优雅字符串

痛点

传统多行字符串使用 \n 和拼接,代码难读难维护。

新特性(JEP 355/368/378)

  • 多行字符串使用 """ 定义
  • 自动处理缩进和换行
  • 支持行连接符 ``

示例

构建 SQL 查询语句、HTML 页面模板、JSON 配置片段。

示例1 - sql 查询

ini 复制代码
String query = """  
    SELECT id, name, email  
    FROM users  
    WHERE status = 'ACTIVE'  
    ORDER BY created_at DESC  
    """;

示例2 - html 模板

ini 复制代码
String html = """  
    <html>  
        <body>  
            <h1>Welcome, %s!</h1>  
        </body>  
    </html>  
    """.formatted(user.getName());

优势:更易编写 JSON、SQL、HTML 等嵌入式文本内容。

3. instanceof 模式匹配:更聪明的类型判断

痛点

类型判断后必须显式强转,重复又冗余。

新特性(JEP 305,JDK 16):

  • 支持 instanceof 时绑定变量

示例

处理请求参数、事件派发、策略模式中类型判断。

scss 复制代码
publicvoidprocess(Object input){  
    if (input instanceof String s) {  
        handleText(s);  
    } elseif (input instanceof Integer i) {  
        handleNumber(i);  
    } else {  
        thrownew IllegalArgumentException("Unsupported input type");  
    }  
}

优势:去除显式强转,更易读、易写、安全。

4. record 类:轻松定义数据载体

痛点

定义一个 POJO** 需要写大量样板代码(构造器、getter、equals 等)。

新特性(JEP 384,JDK 16)

  • 一行代码定义不可变数据类
  • 自动生成构造器、访问器、equalshashCodetoString

示例

用于接口响应对象、查询结果封装、消息体定义

示例1 - 接口响应

csharp 复制代码
public record ApiResponse<T>(int code, String message, T data) {}  
  
ApiResponse<User> response = new ApiResponse<>(200, "OK", user);

示例2 - 封装查询结果

arduino 复制代码
public record UserSummary(String name, int postCount){}  
  
List<UserSummary> summaries = userRepository.getSummaries();

优势:专为数据建模而生,简洁且不易出错。

5. 密封类(Sealed Classes):限制继承范围

痛点

接口或抽象类可以被任意扩展,无法控制子类范围。

新特性(JEP 360,JDK 17)

  • 使用 sealed 修饰类/接口
  • 显式声明允许继承的子类(使用 permits

示例

用于建模流程状态、支付状态、登录结果、事件分发等,确保所有子类都是受控的。

支付状态

arduino 复制代码
public sealed interfacePaymentResultpermitsSuccess, Failure{}  

publicfinalclassSuccessimplementsPaymentResult{  
    String transactionId;  
    // ...  
}  

publicfinalclassFailureimplementsPaymentResult{  
    String reason;  
    // ...  
}

处理支付结果:

scss 复制代码
voidhandle(PaymentResult result){  
    if (result instanceof Success s) {  
        log("Success: " + s.transactionId());  
    } elseif (result instanceof Failure f) {  
        log("Failure: " + f.reason());  
    }  
}

优势:提供受控扩展,便于在模式匹配和状态建模中使用。

web 应用中的实际使用

我们假设 web 应用有以下功能:用户提交订单后,系统处理订单并返回处理结果(成功、库存不足、支付失败等状态)。

1. 使用 record 定义响应对象与 DTO

文件:OrderRequest.java

vbnet 复制代码
public record OrderRequest(Long userId, List<Long> productIds, String paymentType){}

文件:OrderResponse.java

arduino 复制代码
public record OrderResponse(String orderNo, String message, int code){}

用途:

  • 在 Controller** 层接收请求/返回响应;
  • 省略 getter/setter/构造器;
  • 天然不可变,适合并发和函数式风格。

2. 使用 sealed + instanceof 进行订单结果建模和处理

文件:OrderResult.java

typescript 复制代码
public sealed interfaceOrderResultpermitsOrderSuccess, OrderFailure{}  

publicfinalclassOrderSuccessimplementsOrderResult{  
    publicfinal String orderNo;  
    publicOrderSuccess(String orderNo){  
        this.orderNo = orderNo;  
    }  
}  

publicfinalclassOrderFailureimplementsOrderResult{  
    publicfinal String reason;  
    publicOrderFailure(String reason){  
        this.reason = reason;  
    }  
}

在 Service 中处理结果:

java 复制代码
public OrderResponse handleResult(OrderResult result){  
    if (result instanceof OrderSuccess success) {  
        returnnew OrderResponse(success.orderNo, "下单成功", 200);  
    } elseif (result instanceof OrderFailure failure) {  
        returnnew OrderResponse(null, failure.reason, 500);  
    }  
    thrownew IllegalStateException("未知结果类型");  
}

优点:

  • 明确约束返回类型;
  • 避免非法实现或扩展;
  • 结合 instanceof 模式匹配,写法简洁明了。

3. 使用 switch 表达式处理支付类型

文件:PaymentType.java(枚举)

rust 复制代码
publicenum PaymentType {  
    CREDIT_CARD, WECHAT, ALIPAY  
}

在 Service 层选择支付服务:

typescript 复制代码
public PaymentService getPaymentService(PaymentType type){  
    returnswitch (type) {  
        case CREDIT_CARD -> creditCardService;  
        case WECHAT -> wechatPayService;  
        case ALIPAY -> aliPayService;  
    };  
}

优点:

  • 替代 if-else,代码更整洁;
  • 编译器检查是否遗漏分支。

4. 使用文本块生成 SQL 或消息模板

在 Repository 中写动态 SQL:

ini 复制代码
String sql = """  
    SELECT * FROM orders  
    WHERE user_id = ?  
    AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)  
    ORDER BY created_at DESC  
    """;

发送邮件或通知模板:

ini 复制代码
String content = """  
    亲爱的用户,您的订单已成功创建:  
    订单编号:%s  
    总金额:%.2f 元  
    感谢您的购买!  
    """.formatted(orderNo, totalAmount);

优点:

  • 无需拼接;
  • 保持结构清晰,适合业务模板开发。

5. Controller 层综合调用示例

less 复制代码
@RestController  
@RequestMapping("/orders")  
publicclassOrderController{  
  
    @PostMapping  
    public ResponseEntity<OrderResponse> placeOrder(@RequestBody OrderRequest request){  
        OrderResult result = orderService.createOrder(request);  
        OrderResponse response = orderService.handleResult(result);  
        return ResponseEntity.status(response.code()).body(response);  
    }  
}

总结

特性 实际作用 模块
record 快速构建不可变 DTO 与响应体 Controller/DTO
sealed 精确限定子类,建模业务状态 Service/Domain
instanceof 模式匹配 简洁判断不同业务返回类型 Service
switch 表达式 优雅地分发策略/状态处理 Service
文本块 结构化模板与 SQL 管理更清晰 Repository/通知模板

总结一览表

新特性总结:

特性 JEP Java 版本 优势
switch 表达式 325/354/361 12-14 表达式化、安全简洁
文本块 355/368/378 13-15 编写多行字符串更自然
instanceof 模式匹配 305 16 去除强转,增强可读性
record 类 384 16 快速定义不可变数据类
密封类 360 17 限制继承,提高建模安全性

最佳使用场景总结:

特性 实践推荐场景 说明
switch 表达式 状态判断、分支处理、枚举映射 替代复杂 if-else
文本块 SQL/HTML/JSON 模板、配置文件构造 可读性强
instanceof 模式匹配 类型分发、策略切换、事件处理 精简类型判断
record 类 响应对象、DTO、只读配置结构体 最适合不可变数据
密封类 状态机建模、业务结果分类、事件系统 编译时安全的继承控制

写在最后

从 JDK 12 到 JDK 17,Java 逐步摆脱了"啰嗦语言"的帽子,走上了现代化转型之路。这些语法特性使得日常开发更高效、代码更简洁,也更易于维护。

未来的 Java 不再只是"企业级"稳重代名词,它正在变得更轻盈、更聪明------值得每一位开发者重新审视与拥抱。

相关推荐
偷懒下载原神1 小时前
【linux操作系统】信号
linux·运维·服务器·开发语言·c++·git·后端
SmartBrain2 小时前
Spring Boot 中常用注解总结(AI工程化)
java·人工智能·spring boot·后端
小江的记录本2 小时前
【Redis】Redis常用命令速查表(完整版)
java·前端·数据库·redis·后端·spring·缓存
AMoon丶2 小时前
Golang--垃圾回收
java·linux·开发语言·jvm·后端·算法·golang
Densen20142 小时前
企业H5站点升级PWA (二)
java·后端·spring
用户2190326527352 小时前
部署OpenClaw整合QQ机器人
后端
后端不背锅2 小时前
服务网格 Istio:微服务架构的下一步
后端
编码忘我2 小时前
java并发之ThredLocal
后端
Cache技术分享2 小时前
360. Java IO API - 访问文件系统
前端·后端