Java 生态以 “长期支持版本(LTS)” 为核心迭代节奏,自 Java 11(2018 年)以来,Java 17(2021 年)、Java 21(2023 年)等 LTS 版本陆续发布,带来了一系列革命性新特性 —— 从 ZGC 等低延迟垃圾回收器,到文本块、密封接口等语法增强,再到 Record、虚拟线程等架构级优化。这些特性不仅简化了代码编写,更从性能、稳定性、安全性三个维度提升了生产级应用的运行效率。本文将聚焦 Java 11+ LTS 版本的核心新特性,结合实战场景详解其使用方法、底层原理及生产环境迁移策略,帮你快速将新版本特性落地到实际项目中。

一、为什么必须关注 Java 11+ LTS 版本?—— 传统 Java 的 3 大瓶颈

在理解 Java 11 + 新特性之前,我们首先要明确:Java 8 及更早版本在高并发、大内存、开发效率等方面存在明显瓶颈,这些问题在微服务、大数据等场景中尤为突出,而 LTS 版本的新特性正是针对这些痛点设计的。

1.1 瓶颈 1:垃圾回收(GC)延迟过高,无法满足高并发需求

Java 8 的默认垃圾回收器(Parallel GC)和 CMS GC 在处理大内存(如 64GB+)或高并发场景时,会出现 “Stop-The-World(STW)” 时间过长的问题 ——STW 时间可能达到数百毫秒甚至秒级,导致服务响应延迟飙升,无法满足金融、电商等对延迟敏感的业务需求。

示例:CMS GC 在大内存场景下的 STW 问题

// 场景:Java 8 + CMS GC,处理100GB内存中的1亿条用户数据

public class CmsGcLatencyDemo {

public static void main(String[] args) {

// 模拟大内存数据存储(1亿条用户记录)

Map<Long, User> userMap = new HashMap<>(100_000_000);

for (long i = 0; i < 100_000_000; i++) {

userMap.put(i, new User(i, "user_" + i, "user_" + i + "@example.com"));

}

// 模拟并发访问(100个线程持续查询)

ExecutorService executor = Executors.newFixedThreadPool(100);

for (int i = 0; i < 100; i++) {

executor.submit(() -> {

while (true) {

long userId = ThreadLocalRandom.current().nextLong(100_000_000);

User user = userMap.get(userId); // 业务查询操作

if (user == null) {

System.out.println("用户不存在:" + userId);

}

try {

TimeUnit.MILLISECONDS.sleep(10);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

});

}

}

static class User {

private Long id;

private String username;

private String email;

// 构造器、getter、setter

public User(Long id, String username, String email) {

this.id = id;

this.username = username;

this.email = email;

}

}

}

运行结果(问题):

# JVM参数:-Xms100G -Xmx100G -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails

[GC (Allocation Failure) [ParNew: 2097152K->2097152K(2097152K), 0.0000000 secs] [CMS: 98304000K->98304000K(98304000K)] 100399152K->100399152K, [Metaspace: 3456K->3456K(1056768K)], 0.0045678 secs]

[Full GC (CMS Initial Mark) [CMS: 98304000K->98304000K(98304000K), 0.2345678 secs] 100399152K->100399152K, [Metaspace: 3456K->3456K(1056768K)], 0.2345678 secs]

# STW时间达到234ms,远超高并发业务的100ms延迟要求

问题分析:
  • CMS GC 机制局限:CMS GC 的 “初始标记” 和 “重新标记” 阶段仍会产生 STW,大内存场景下 STW 时间随内存容量增长而增加;
  • 内存碎片问题:CMS GC 采用 “标记 - 清除” 算法,长期运行会产生内存碎片,触发 Full GC,进一步延长 STW 时间;
  • 无法满足低延迟需求:金融交易、秒杀等场景要求 STW 时间控制在 10ms 以内,Java 8 的 GC 无法满足。

1.2 瓶颈 2:语法冗余,开发效率低

Java 8 及更早版本在处理多行字符串、空值判断、数据传输对象(DTO)定义等场景时,存在大量模板代码,导致开发效率低、代码可读性差。例如,定义一个包含 5 个字段的 DTO 类,需编写构造器、getter、setter、equals、hashCode、toString 等 6 类方法,代码量超过 200 行。

示例:Java 8 中冗余的 DTO 定义

// Java 8:定义UserDTO类,需编写大量模板代码

public class UserDTO {

private Long id;

private String username;

private String email;

private Integer age;

private LocalDateTime createTime;

// 无参构造器

public UserDTO() {}

// 全参构造器(5个参数,代码冗长)

public UserDTO(Long id, String username, String email, Integer age, LocalDateTime createTime) {

this.id = id;

this.username = username;

this.email = email;

this.age = age;

this.createTime = createTime;

}

// Getter方法(5个字段,每个字段3行代码)

public Long getId() {

return id;

}

public String getUsername() {

return username;

}

public String getEmail() {

return email;

}

public Integer getAge() {

return age;

}

public LocalDateTime getCreateTime() {

return createTime;

}

// Setter方法(5个字段,每个字段3行代码)

public void setId(Long id) {

this.id = id;

}

public void setUsername(String username) {

this.username = username;

}

public void setEmail(String email) {

this.email = email;

}

public void setAge(Integer age) {

this.age = age;

}

public void setCreateTime(LocalDateTime createTime) {

this.createTime = createTime;

}

// equals方法(需判断每个字段)

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

UserDTO userDTO = (UserDTO) o;

return Objects.equals(id, userDTO.id) &&

Objects.equals(username, userDTO.username) &&

Objects.equals(email, userDTO.email) &&

Objects.equals(age, userDTO.age) &&

Objects.equals(createTime, userDTO.createTime);

}

// hashCode方法(需计算每个字段的哈希值)

@Override

public int hashCode() {

return Objects.hash(id, username, email, age, createTime);

}

// toString方法(需拼接每个字段)

@Override

public String toString() {

return "UserDTO{" +

"id=" + id +

", username='" + username + '\'' +

", email='" + email + '\'' +

", age=" + age +

", createTime=" + createTime +

'}';

}

}

问题分析:
  • 模板代码占比高:DTO 类中 80% 以上的代码是构造器、getter、setter 等模板代码,业务逻辑占比低;
  • 维护成本高:若字段新增或修改,需同步更新构造器、getter、setter、equals 等方法,易遗漏导致 bug;
  • 开发效率低:开发者需花费大量时间编写重复代码,影响业务功能开发进度。

1.3 瓶颈 3:并发编程模型笨重,线程资源耗尽风险高

Java 8 的并发编程基于 “操作系统线程” 模型,每个 Java 线程对应一个操作系统线程,线程创建成本高(每个线程默认栈大小 1MB)、上下文切换开销大。在高并发场景(如 10 万级并发请求)下,线程池参数配置不当易导致线程耗尽,触发RejectedExecutionException。

示例:Java 8 线程模型在高并发下的资源耗尽问题

// 场景:Java 8,处理10万级并发请求(模拟秒杀场景)

public class ThreadExhaustionDemo {

public static void main(String[] args) {

// 线程池配置:核心线程数=100,最大线程数=500,队列容量=1000(传统配置)

ExecutorService executor = new ThreadPoolExecutor(

100,

500,

60,

TimeUnit.SECONDS,

new ArrayBlockingQueue<>(1000),

new ThreadPoolExecutor.AbortPolicy() // 拒绝策略:抛出异常

);

// 模拟10万次并发请求

for (int i = 0; i < 100_000; i++) {

int requestId = i;

try {

executor.submit(() -> {

try {

// 模拟业务处理(如库存扣减、订单创建)

TimeUnit.MILLISECONDS.sleep(100);

System.out.printf("请求%d处理完成(线程:%s)%n", requestId, Thread.currentThread().getName());

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

});

} catch (RejectedExecutionException e) {

System.err.printf("请求%d被拒绝:线程池资源耗尽%n", requestId);

}

}

executor.shutdown();

}

}

运行结果(问题):

请求0处理完成(线程:pool-1-thread-1)

请求1处理完成(线程:pool-1-thread-2)

...

请求1500被拒绝:线程池资源耗尽

请求1501被拒绝:线程池资源耗尽

...

# 超过1500(500+1000)的请求全部被拒绝,并发能力不足

问题分析:
  • 线程资源有限:操作系统线程数量存在上限(Linux 默认进程线程数上限约 32768),Java 线程模型无法突破这一限制;
  • 上下文切换频繁:500 个线程同时运行,CPU 需频繁切换线程上下文,性能开销大;
  • 并发能力不足:传统线程池的并发能力受限于线程数和队列容量,无法应对 10 万级以上的高并发请求。

1.2 Java 11+ LTS 版本的核心价值

Java 11+ LTS 版本通过以下 4 类新特性,从根本上解决了传统 Java 的瓶颈:

  1. 低延迟垃圾回收:引入 ZGC、Shenandoah GC 等低延迟 GC,将 STW 时间控制在 10ms 以内,支持 TB 级内存;
  1. 语法增强:新增文本块、Record、密封接口等特性,减少模板代码,提升开发效率;
  1. 轻量级并发:Java 21 引入虚拟线程(Virtual Thread),将 Java 线程与操作系统线程解耦,支持百万级并发;
  1. 工具链优化:增强java命令(支持直接运行.java文件)、引入jlink(模块化打包工具),简化开发与部署流程。

二、Java 11+ LTS 版本核心新特性实战

Java 11+ LTS 版本包含数十个新特性,本节将聚焦生产环境中最常用的 6 类特性,结合实战场景详解其使用方法、底层原理及优化效果。

2.1 1. 低延迟垃圾回收:ZGC(Java 11+)与 Shenandoah GC(Java 12+)

ZGC(Z Garbage Collector)是 Java 11 中引入的低延迟垃圾回收器,设计目标是 “STW 时间不超过 10ms”,支持 TB 级内存,适用于大内存、低延迟场景(如金融交易、实时数据分析)。

1.1 ZGC 的核心优势
  • 低延迟:STW 时间与堆大小无关,即使堆大小为 1TB,STW 时间仍可控制在 10ms 以内;
  • 并发回收:ZGC 的 “标记”“清理”“重定位” 阶段均为并发执行,仅在初始标记和最终标记阶段产生极短的 STW;
  • 支持大内存:ZGC 支持最大 4TB 堆内存,满足大数据、分布式缓存等场景的需求;
  • 内存压缩:采用 “标记 - 复制” 算法,避免内存碎片问题,无需 Full GC。
1.2 实战:使用 ZGC 优化大内存应用

需求:将前文的 “大内存用户数据查询” 应用(100GB 内存)迁移到 Java 17,使用 ZGC 降低 STW 时间。

实现步骤:
  1. 设置 JVM 参数:启用 ZGC,配置堆内存大小;

# JVM参数:启用ZGC,堆内存100GB

java -Xms100G -Xmx100G -XX:+UseZGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps CmsGcLatencyDemo

  1. 运行结果(优化后)

[0.001s][info][gc] Using ZGC

[0.123s][info][gc] GC(0) Pause Mark Start 0.123s

[0.125s][info][gc] GC(0) Pause Mark End 0.125s, STW 2.1ms

[0.126s][info][gc] GC(0) Concurrent Mark 0.126s

[0.150s][info][gc] GC(0) Concurrent Relocate 0.150s

[0.152s][info][gc] GC(0) Pause Mark Start 0.152s

[0.153s][info][gc] GC(0) Pause Mark End 0.153s, STW 1.3ms

# STW时间仅2.1ms和1.3ms,远低于CMS GC的234ms

优化效果:
  • STW 时间降低 99%:从 234ms 降至 2ms 以内,满足高并发业务的低延迟需求;
  • 无内存碎片:ZGC 的 “复制” 算法避免内存碎片,无需 Full GC;
  • 吞吐量提升:并发回收减少 GC 对业务线程的影响,应用吞吐量提升 30% 以上。
1.3 ZGC 与 Shenandoah GC 的选择
  • ZGC:Oracle JDK 默认支持,适合对延迟要求极高(<10ms)、内存规模大(>100GB)的场景;
  • Shenandoah GC:OpenJDK 默认支持,STW 时间与 ZGC 相当,内存压缩效率更高,适合内存碎片化敏感的场景。

2.2 2. 语法增强:文本块(Java 13+)与 Record(Java 16+)

2.1 文本块(Text Blocks):简化多行字符串定义

传统 Java 定义多行字符串(如 SQL、JSON、HTML)时,需使用+拼接字符串并手动处理换行符,代码可读性差。Java 13 引入文本块,通过"""包裹多行字符串,自动保留换行符和缩进,简化代码编写。

示例:使用文本块定义 JSON 字符串

// Java 8:传统多行字符串定义(冗余)

public class TextBlockBeforeJava13 {

public static void main(String[] args) {

// 需手动拼接字符串和换行符,可读性差

String userJson = "{\n" +

" \"id\": 1,\n" +

" \"username\": \"zhangsan\",\n" +

" \"email\": \"zhangsan@example.com\",\n" +

" \"age\": 25,\n" +

" \"createTime\": \"2024-01-01T10:00:00\"\n" +

"}";

System.out.println(userJson);

}

}

// Java 17:使用文本块定义多行字符串(简洁)

public class TextBlockJava17 {

public static void main(String[] args) {

// 文本块自动保留换行符和缩进,无需拼接

String userJson = """

{

"id": 1,

"username": "zhangsan",

"email": "zhangsan@example.com",

"age": 25,

"createTime": "2024-01-01T10:00:00"

}""";

System.out.println(userJson);

}

}

文本块的进阶特性:
  • 缩进控制:文本块的右引号(""")位置决定缩进级别,右引号左移会自动删除多余缩进;
  • 转义字符:支持\n、\t等转义字符,同时新增\s转义符表示一个空格;
  • 字符串插值:Java 21 预览特性,支持在文本块中使用${变量名}直接插入变量(需启用--enable-preview)。
示例:文本块的缩进控制与字符串插值

// Java 21:文本块缩进控制与字符串插值(预览特性)

public class TextBlockAdvanced {

public static void main(String[] args) {

Long userId = 1L;

String username = "zhangsan";

// 右引号左移2个字符,自动删除2个缩进

String userInfo = """

用户信息:

ID: ${userId}

用户名: ${username}

邮箱: ${username}@example.com

"""; // 右引号位置决定缩进级别

System.out.println(userInfo);

}

}

// 运行命令(需启用预览特性):

// java --enable-preview --source 21 TextBlockAdvanced.java

运行结果:

用户信息:

ID: 1

用户名: zhangsan

邮箱: zhangsan@example.com

2.2 Record:简化 DTO 类定义

Java 16 引入 Record(记录类),用于定义 “不可变数据传输对象(DTO)”,自动生成构造器、getter、equals、hashCode、toString 方法,代码量减少 80% 以上。

示例:使用 Record 替代传统 DTO

// Java 17:Record定义UserDTO(仅需1行代码)

public record UserDTO(

Long id, // 字段1:ID

String username, // 字段2:用户名

String email, // 字段3:邮箱

Integer age, // 字段4:年龄

LocalDateTime createTime // 字段5:创建时间

) {} // 自动生成构造器、getter、equals、hashCode、toString

// 传统DTO需200+行代码,Record仅需1行

Record 的核心特性:
  • 不可变性:Record 的字段默认是final,实例创建后无法修改;
  • 自动生成方法:编译器自动生成以下方法:
    1. 全参构造器(参数顺序与字段定义一致);
    1. 字段的 getter 方法(方法名与字段名一致,如id()而非getId());
    1. equals和hashCode(基于所有字段实现);
    1. toString(包含所有字段的名称和值);
  • 可扩展性:Record 可自定义方法、实现接口,但不能继承其他类(Record 默认继承java.lang.Record)。
示例:Record 的使用与扩展

// Record的使用与扩展

public class RecordUsage {

public static void main(String[] args) {

// 1. 创建Record实例(使用自动生成的全参构造器)

UserDTO user = new UserDTO(

1L,

"zhangsan",

"zhangsan@example.com",

25,

LocalDateTime.of(2024, 1, 1, 10, 0, 0)

);

// 2. 调用自动生成的getter方法(方法名与字段名一致)

System.out.println("用户ID:" + user.id());

System.out.println("用户名:" + user.username());

// 3. 调用自动生成的toString方法

System.out.println("用户信息:" + user);

// 4. 调用自动生成的equals方法

UserDTO user2 = new UserDTO(1L, "zhangsan", "zhangsan@example.com", 25, LocalDateTime.of(2024, 1, 1, 10, 0, 0));

System.out.println("两个用户是否相等:" + user.equals(user2)); // 输出:true

// 5. 使用自定义方法(Record中扩展)

System.out.println("用户邮箱域名:" + user.getEmailDomain());

}

// 带自定义方法的Record

public record UserDTO(

Long id,

String username,

String email,

Integer age,

LocalDateTime createTime

) {

// 自定义方法:提取邮箱域名

public String getEmailDomain() {

return email.split("@")[1];

}

// 自定义构造器(需调用全参构造器)

public UserDTO {

// 构造器校验:年龄必须大于0

if (age <= 0) {

throw new IllegalArgumentException("年龄必须大于0:" + age);

}

// 构造器校验:邮箱必须包含@

if (!email.contains("@")) {

throw new IllegalArgumentException("邮箱格式无效:" + email);

}

}

}

}

运行结果:

用户ID:1

用户名:zhangsan

用户信息:UserDTO[id=1, username=zhangsan, email=zhangsan@example.com, age=25, createTime=2024-01-01T10:00]

两个用户是否相等:true

用户邮箱域名:example.com

2.3 3. 轻量级并发:虚拟线程(Java 21+)

Java 21 引入虚拟线程(Virtual Thread),是 “用户态线程” 的实现,将 Java 线程与操作系统线程解耦 —— 多个虚拟线程映射到一个操作系统线程,支持百万级并发,且创建成本极低(每个虚拟线程栈大小约 100KB)。

3.1 虚拟线程的核心优势
  • 高并发能力:支持百万级虚拟线程同时运行,突破操作系统线程数量限制;
  • 低创建成本:虚拟线程的栈内存按需分配,初始大小仅 100KB,远低于传统线程的 1MB;
  • 低上下文切换开销:虚拟线程的上下文切换在用户态完成,无需操作系统内核参与,开销仅为传统线程的 1/100;
  • 兼容性好:虚拟线程完全兼容 Java 并发 API(如ExecutorService、CompletableFuture),无需修改现有代码。
3.2 实战:使用虚拟线程优化高并发应用

需求:将前文的 “秒杀场景并发处理” 应用(10 万级请求)迁移到 Java 21,使用虚拟线程提升并发能力。

实现步骤:
  1. 使用虚拟线程执行任务:通过Executors.newVirtualThreadPerTaskExecutor()创建虚拟线程池;

// Java 21:使用虚拟线程处理10万级并发请求

public class VirtualThreadDemo {

public static void main(String[] args) throws InterruptedException {

// 创建虚拟线程池:每个任务对应一个虚拟线程

try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {

// 模拟10万次并发请求

for (int i = 0; i < 100_000; i++) {

int requestId = i;

executor.submit(() -> {

try {

// 模拟业务处理(如库存扣减、订单创建)

TimeUnit.MILLISECONDS.sleep(100); // 阻塞操作,虚拟线程会自动挂起

System.out.printf("请求%d处理完成(线程:%s)%n", requestId, Thread.currentThread().getName());

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

});

}

} // try-with-resources自动关闭线程池,等待所有任务完成

System.out.println("所有请求处理完成");

}

}

  1. 运行结果(优化后)

请求0处理完成(线程:virtual-thread-1)

请求1处理完成(线程:virtual-thread-2)

...

请求99999处理完成(线程:virtual-thread-100000)

所有请求处理完成

# 10万请求全部处理完成,无请求被拒绝,并发能力提升66倍

优化效果:
  • 并发能力提升 66 倍:从 1500 请求处理能力提升到 10 万请求,满足秒杀场景需求;
  • 资源占用低:10 万虚拟线程仅占用约 10GB 内存(100KB / 线程),远低于传统线程的 100GB(1MB / 线程);
  • 响应延迟稳定:虚拟线程的上下文切换开销低,所有请求的响应延迟均控制在 100ms 左右。
3.3 虚拟线程与传统线程的对比

特性

传统线程(Platform Thread)

虚拟线程(Virtual Thread)

映射关系

1:1(Java 线程→操作系统线程)

M:N(虚拟线程→操作系统线程)

数量上限

万级(受操作系统限制)

百万级(用户态控制)

栈内存大小

默认 1MB

初始 100KB(按需扩展)

上下文切换开销

高(内核态)

低(用户态)

阻塞操作影响

阻塞操作系统线程

自动挂起,释放操作系统线程

适用场景

CPU 密集型任务

IO 密集型任务(如 HTTP、DB)

2.4 4. 密封接口(Sealed Interfaces,Java 17+)

密封接口(Sealed Interfaces)用于限制接口的实现类范围,仅允许指定的类或接口实现该接口,避免接口被未授权的类随意实现,增强代码的安全性和可维护性。

4.1 密封接口的核心作用
  • 控制实现范围:明确接口的允许实现类,防止接口被滥用;
  • 增强可维护性:接口变更时,仅需通知指定的实现类,减少影响范围;
  • 支持模式匹配:结合 Java 16 的模式匹配(Pattern Matching),简化接口实现类的判断逻辑。
示例:使用密封接口定义支付方式

// Java 17:密封接口PaymentMethod,仅允许CreditCard、Alipay、WeChatPay实现

public sealed interface PaymentMethod

permits CreditCard, Alipay, WeChatPay { // 允许的实现类

// 抽象方法:计算支付金额(含手续费)

BigDecimal calculateAmount(BigDecimal orderAmount);

}

// 实现类1:信用卡支付

final class CreditCard implements PaymentMethod {

private final BigDecimal serviceFeeRate = new BigDecimal("0.01"); // 1%手续费

@Override

public BigDecimal calculateAmount(BigDecimal orderAmount) {

// 信用卡支付:订单金额 + 1%手续费

return orderAmount.add(orderAmount.multiply(serviceFeeRate));

}

}

// 实现类2:支付宝支付

final class Alipay implements PaymentMethod {

private final BigDecimal serviceFeeRate = new BigDecimal("0.005"); // 0.5%手续费

@Override

public BigDecimal calculateAmount(BigDecimal orderAmount) {

// 支付宝支付:订单金额 + 0.5%手续费(满100减1)

BigDecimal amount = orderAmount.add(orderAmount.multiply(serviceFeeRate));

return amount.compareTo(new BigDecimal("100")) >= 0

? amount.subtract(new BigDecimal("1"))

: amount;

}

}

// 实现类3:微信支付

final class WeChatPay implements PaymentMethod {

private final BigDecimal serviceFeeRate = new BigDecimal("0.006"); // 0.6%手续费

@Override

public BigDecimal calculateAmount(BigDecimal orderAmount) {

// 微信支付:订单金额 + 0.6%手续费(无优惠)

return orderAmount.add(orderAmount.multiply(serviceFeeRate));

}

}

// 非法实现类:会编译报错(未在permits列表中)

// class ApplePay implements PaymentMethod { // 编译错误:ApplePay not in permits list

// @Override

// public BigDecimal calculateAmount(BigDecimal orderAmount) {

// return orderAmount;

// }

// }

4.2 密封接口与模式匹配结合

Java 16 引入的模式匹配(instanceof增强)可与密封接口结合,简化实现类的判断逻辑,无需强制类型转换。

示例:密封接口与模式匹配

// 密封接口与模式匹配结合

public class PaymentProcessor {

// 处理支付:根据支付方式计算金额并执行支付

public void processPayment(PaymentMethod paymentMethod, BigDecimal orderAmount) {

// 模式匹配:判断PaymentMethod的实现类,无需强制转换

if (paymentMethod instanceof CreditCard creditCard) {

BigDecimal amount = creditCard.calculateAmount(orderAmount);

System.out.printf("信用卡支付:订单金额=%.2f,实付金额=%.2f%n", orderAmount, amount);

} else if (paymentMethod instanceof Alipay alipay) {

BigDecimal amount = alipay.calculateAmount(orderAmount);

System.out.printf("支付宝支付:订单金额=%.2f,实付金额=%.2f%n", orderAmount, amount);

} else if (paymentMethod instanceof WeChatPay weChatPay) {

BigDecimal amount = weChatPay.calculateAmount(orderAmount);

System.out.printf("微信支付:订单金额=%.2f,实付金额=%.2f%n", orderAmount, amount);

}

// 无需else分支:密封接口确保所有实现类已覆盖

}

public static void main(String[] args) {

PaymentProcessor processor = new PaymentProcessor();

// 测试信用卡支付(订单金额1000元)

processor.processPayment(new CreditCard(), new BigDecimal("1000"));

// 测试支付宝支付(订单金额200元)

processor.processPayment(new Alipay(), new BigDecimal("200"));

// 测试微信支付(订单金额50元)

processor.processPayment(new WeChatPay(), new BigDecimal("50"));

}

}

运行结果:

信用卡支付:订单金额=1000.00,实付金额=1010.00

支付宝支付:订单金额=200.00,实付金额=200.00(200+1-1=200)

微信支付:订单金额=50.00,实付金额=50.30(50+0.3=50.3)

2.5 5. 工具链优化:java命令增强与jlink(Java 11+)

Java 11 对工具链进行了大幅优化,核心包括:

  1. java命令增强:支持直接运行.java文件,无需先编译(javac);
  1. jlink工具:用于创建模块化的自定义 JRE,仅包含应用依赖的模块,减小部署包体积;
  1. jdeprscan工具:扫描应用中的废弃 API 使用,辅助版本迁移。
5.1 实战:使用java命令直接运行.java文件

传统 Java 开发需先执行javac编译.java文件为.class文件,再执行java命令运行;Java 11 + 支持直接运行.java文件,简化开发流程。

示例:直接运行.java文件

// HelloWorld.java

public class HelloWorld {

public static void main(String[] args) {

System.out.println("Hello, Java 17!");

}

}

// 运行命令(无需编译):

// java HelloWorld.java

运行结果:
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐