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 不再只是"企业级"稳重代名词,它正在变得更轻盈、更聪明------值得每一位开发者重新审视与拥抱。

相关推荐
Chenyiax8 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH8 小时前
Koa和Express的区别
后端
MariaH9 小时前
Koa框架的使用
后端
luckdewei10 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某11 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy11 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom11 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github
用户14748530797415 小时前
CodeX使用Skill生成游戏美术和音乐资源,一分钟入门
后端
Melody12316 小时前
用 abort 中断 AI 流式请求,我之前做错了
后端
onething36516 小时前
Spring Boot + Spring AI 从入门到实战:7天转型计划 Day 5 —— SSE 流式输出 + 打字机效果
人工智能·后端·全栈