引言
在第一期的全面概览中,我们了解了JDK 17作为LTS版本的重要意义和完整的特性图谱。从本期开始,我们将深入每个技术领域的细节。第二期聚焦于JDK 17最引人注目的语言特性革新。
这些语言特性不仅仅是语法糖,而是Java语言设计哲学的重要演进:
- 密封类(Sealed Classes):实现精确的类型控制和安全的继承层次
- Switch模式匹配:带来函数式编程的优雅表达
- Record类型进阶:现代化的数据建模方案
本期将通过实际案例、最佳实践和设计原理的深度分析,帮助您完全掌握这些特性的精髓。
目录
一、密封类完全指南
1.1 密封类的核心理念
密封类(Sealed Classes)解决了Java长期存在的一个设计难题:如何在开放的继承体系中实现精确的类型控制。
传统继承的问题
java
// 传统方式:无法控制继承层次
public abstract class Shape {
public abstract double area();
}
// 任何人都可以继承,破坏了设计意图
public class WeirdShape extends Shape {
@Override
public double area() {
return Double.NaN; // 意外的实现
}
}
问题分析:
- 无法限制谁可以继承抽象类
- 开关语句无法穷尽所有可能的子类
- 代码维护困难,容易引入意外的类型
密封类的解决方案
java
// JDK 17:精确控制的继承层次
public sealed class Shape
permits Circle, Rectangle, Triangle {
public abstract double area();
}
// 只有显式允许的类才能继承
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public final class Rectangle extends Shape {
private final double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
public non-sealed class Triangle extends Shape {
// non-sealed 允许进一步继承
private final double base, height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
}
1.2 密封类的三种修饰符
1. final
- 禁止继承
java
public final class Circle extends Shape {
// 不能被进一步继承
}
2. sealed
- 受控继承
java
public sealed class Polygon extends Shape
permits Triangle, Quadrilateral {
// 只有指定的类可以继承
}
3. non-sealed
- 重新开放继承
java
public non-sealed class Triangle extends Polygon {
// 允许任意继承
}
// 现在可以自由继承Triangle
public class IsoscelesTriangle extends Triangle {
// 合法的继承
}
1.3 密封接口的强大应用
密封接口特别适合建模代数数据类型(ADT):
java
// 函数式编程风格的结果类型
public sealed interface Result<T, E>
permits Result.Success, Result.Failure {
// 嵌套记录类型,完美结合
record Success<T, E>(T value) implements Result<T, E> {}
record Failure<T, E>(E error) implements Result<T, E> {}
// 类型安全的变换操作
default <R> Result<R, E> map(Function<T, R> mapper) {
return switch (this) {
case Success<T, E>(var value) ->
new Success<>(mapper.apply(value));
case Failure<T, E>(var error) ->
new Failure<>(error);
};
}
// 错误处理的函数式组合
default <F> Result<T, F> mapError(Function<E, F> mapper) {
return switch (this) {
case Success<T, E>(var value) ->
new Success<>(value);
case Failure<T, E>(var error) ->
new Failure<>(mapper.apply(error));
};
}
// 链式操作
default <R> Result<R, E> flatMap(Function<T, Result<R, E>> mapper) {
return switch (this) {
case Success<T, E>(var value) ->
mapper.apply(value);
case Failure<T, E>(var error) ->
new Failure<>(error);
};
}
}
使用示例:
java
public class FileProcessor {
public Result<String, IOException> readFile(String path) {
try {
String content = Files.readString(Paths.get(path));
return new Result.Success<>(content);
} catch (IOException e) {
return new Result.Failure<>(e);
}
}
public Result<Integer, String> parseNumber(String text) {
try {
int number = Integer.parseInt(text.trim());
return new Result.Success<>(number);
} catch (NumberFormatException e) {
return new Result.Failure<>("Invalid number format: " + text);
}
}
// 函数式组合的威力
public Result<Integer, String> processFile(String path) {
return readFile(path)
.mapError(IOException::getMessage) // 转换错误类型
.flatMap(this::parseNumber); // 链式处理
}
}
// 优雅的使用方式
var result = processor.processFile("data.txt");
String output = switch (result) {
case Result.Success<Integer, String>(var value) ->
"Number: " + value;
case Result.Failure<Integer, String>(var error) ->
"Error: " + error;
};
1.4 密封类的设计模式
状态机模式
java
public sealed interface ConnectionState
permits Disconnected, Connecting, Connected, Error {
record Disconnected() implements ConnectionState {}
record Connecting(String host, int port) implements ConnectionState {}
record Connected(Socket socket, long establishedAt) implements ConnectionState {}
record Error(String message, Throwable cause) implements ConnectionState {}
}
public class NetworkConnection {
private ConnectionState state = new ConnectionState.Disconnected();
public void connect(String host, int port) {
state = switch (state) {
case ConnectionState.Disconnected() -> {
// 开始连接
yield new ConnectionState.Connecting(host, port);
}
case ConnectionState.Connecting(var h, var p) -> {
yield new ConnectionState.Error(
"Already connecting",
new IllegalStateException()
);
}
case ConnectionState.Connected(var socket, var time) -> {
yield new ConnectionState.Error(
"Already connected",
new IllegalStateException()
);
}
case ConnectionState.Error(var msg, var cause) -> {
// 允许重新连接
yield new ConnectionState.Connecting(host, port);
}
};
}
public boolean isReady() {
return switch (state) {
case ConnectionState.Connected(var socket, var time) -> true;
case ConnectionState.Disconnected(),
ConnectionState.Connecting(var host, var port),
ConnectionState.Error(var msg, var cause) -> false;
};
}
}
二、Switch模式匹配详解
2.1 从传统Switch到模式匹配的演进
传统Switch的局限性
java
// JDK 14之前:冗长且容易出错
public String describe(Object obj) {
String result;
if (obj instanceof String) {
String s = (String) obj;
result = "String: " + s;
} else if (obj instanceof Integer) {
Integer i = (Integer) obj;
result = "Integer: " + i;
} else if (obj instanceof List) {
List<?> list = (List<?>) obj;
result = "List with " + list.size() + " elements";
} else {
result = "Unknown type";
}
return result;
}
JDK 17的模式匹配革命
java
// JDK 17:简洁且类型安全
public String describe(Object obj) {
return switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case List<?> list -> "List with " + list.size() + " elements";
case null -> "null value";
default -> "Unknown type: " + obj.getClass().getSimpleName();
};
}
2.2 模式匹配的核心语法
1. 类型模式(Type Patterns)
java
public double calculateArea(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
// 密封类确保这里是穷尽的
};
}
2. 守卫条件(Guard Conditions)
java
public String categorizeNumber(Object obj) {
return switch (obj) {
case Integer i when i < 0 -> "Negative integer";
case Integer i when i == 0 -> "Zero";
case Integer i when i > 0 && i < 100 -> "Small positive integer";
case Integer i -> "Large integer";
case Double d when d.isNaN() -> "Not a number";
case Double d when d.isInfinite() -> "Infinite";
case Double d -> "Double: " + d;
default -> "Not a number";
};
}
3. 解构模式(Deconstruction Patterns)
java
// Record类型的解构
public record Point(int x, int y) {}
public record Circle(Point center, double radius) {}
public String analyzeCircle(Circle circle) {
return switch (circle) {
case Circle(Point(0, 0), double r) ->
"Circle at origin with radius " + r;
case Circle(Point(int x, int y), double r) when x == y ->
"Circle on diagonal at (" + x + "," + y + ")";
case Circle(Point(int x, int y), double r) when r > 10 ->
"Large circle at (" + x + "," + y + ")";
case Circle(var center, var radius) ->
"Circle at " + center + " with radius " + radius;
};
}
2.3 高级模式匹配技巧
嵌套模式匹配
java
public record Order(String id, List<Item> items) {}
public record Item(String name, int quantity, double price) {}
public String processOrder(Order order) {
return switch (order) {
// 空订单
case Order(var id, var items) when items.isEmpty() ->
"Empty order: " + id;
// 单项订单
case Order(var id, var items) when items.size() == 1 ->
switch (items.get(0)) {
case Item(var name, int qty, double price) when qty > 10 ->
"Bulk order: " + qty + "x " + name;
case Item(var name, var qty, var price) ->
"Single item: " + name;
};
// 多项订单
case Order(var id, var items) -> {
double total = items.stream()
.mapToDouble(item -> item.quantity() * item.price())
.sum();
yield "Order " + id + " total: $" + total;
}
};
}
数组和集合的模式匹配
java
public String analyzeArray(int[] array) {
return switch (array) {
case null -> "null array";
case int[] arr when arr.length == 0 -> "empty array";
case int[] arr when arr.length == 1 -> "single element: " + arr[0];
case int[] arr when arr.length == 2 ->
"pair: [" + arr[0] + ", " + arr[1] + "]";
case int[] arr -> "array with " + arr.length + " elements";
};
}
// 注意:JDK 17对集合的解构支持有限,但可以通过自定义模式实现
public String analyzeList(List<String> list) {
return switch (list.size()) {
case 0 -> "empty list";
case 1 -> "single item: " + list.get(0);
case 2 -> "pair: [" + list.get(0) + ", " + list.get(1) + "]";
default -> "list with " + list.size() + " items";
};
}
三、Record类型进阶应用
3.1 Record的深层设计理念
Record类型不仅仅是简化的数据容器,它体现了现代Java对值对象(Value Objects)的官方支持。
值对象的特征
java
// 传统方式:大量样板代码
public final class PersonOld {
private final String name;
private final int age;
private final String email;
public PersonOld(String name, int age, String email) {
this.name = Objects.requireNonNull(name);
this.age = age;
this.email = Objects.requireNonNull(email);
}
public String name() { return name; }
public int age() { return age; }
public String email() { return email; }
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
PersonOld person = (PersonOld) obj;
return age == person.age &&
Objects.equals(name, person.name) &&
Objects.equals(email, person.email);
}
@Override
public int hashCode() {
return Objects.hash(name, age, email);
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age +
", email='" + email + "'}";
}
}
// Record方式:简洁且功能完整
public record Person(String name, int age, String email) {
// 自动生成构造器、访问器、equals、hashCode、toString
// 可以添加验证逻辑
public Person {
Objects.requireNonNull(name, "Name cannot be null");
Objects.requireNonNull(email, "Email cannot be null");
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
}
}
3.2 Record的高级特性
1. 紧凑构造器(Compact Constructor)
java
public record Temperature(double value, String unit) {
// 紧凑构造器:无需声明参数
public Temperature {
// 数据验证和标准化
Objects.requireNonNull(unit, "Unit cannot be null");
unit = unit.toUpperCase();
// 温度合理性检查
switch (unit) {
case "C", "CELSIUS" -> {
if (value < -273.15) {
throw new IllegalArgumentException("Temperature below absolute zero");
}
}
case "F", "FAHRENHEIT" -> {
if (value < -459.67) {
throw new IllegalArgumentException("Temperature below absolute zero");
}
}
case "K", "KELVIN" -> {
if (value < 0) {
throw new IllegalArgumentException("Kelvin cannot be negative");
}
}
default -> throw new IllegalArgumentException("Unknown unit: " + unit);
}
}
// 添加便利方法
public Temperature toCelsius() {
return switch (unit.toUpperCase()) {
case "C", "CELSIUS" -> this;
case "F", "FAHRENHEIT" -> new Temperature((value - 32) * 5.0/9.0, "C");
case "K", "KELVIN" -> new Temperature(value - 273.15, "C");
default -> throw new IllegalStateException("Invalid unit: " + unit);
};
}
public boolean isFreezing() {
return toCelsius().value() <= 0;
}
public boolean isBoiling() {
return toCelsius().value() >= 100;
}
}
2. Record的继承和接口实现
java
// Record可以实现接口
public interface Drawable {
void draw();
default void highlight() {
System.out.println("Highlighting " + this);
}
}
public interface Measurable {
double area();
default double perimeter() {
return 0; // 默认实现
}
}
// Record实现多个接口
public record Circle(double radius) implements Drawable, Measurable {
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
// 添加静态工厂方法
public static Circle unit() {
return new Circle(1.0);
}
public static Circle fromDiameter(double diameter) {
return new Circle(diameter / 2.0);
}
}
3. 嵌套Record和泛型Record
java
// 泛型Record
public record Result<T, E>(T value, E error, boolean isSuccess) {
// 成功结果的工厂方法
public static <T, E> Result<T, E> success(T value) {
return new Result<>(value, null, true);
}
// 失败结果的工厂方法
public static <T, E> Result<T, E> failure(E error) {
return new Result<>(null, error, false);
}
// 类型安全的值获取
public Optional<T> getValue() {
return isSuccess ? Optional.of(value) : Optional.empty();
}
public Optional<E> getError() {
return isSuccess ? Optional.empty() : Optional.of(error);
}
}
// 复杂的嵌套数据结构
public record ApiResponse<T>(
boolean success,
T data,
ErrorInfo error,
Metadata meta
) {
// 嵌套Record
public record ErrorInfo(String code, String message, long timestamp) {}
public record Metadata(
String requestId,
long processingTime,
String version
) {}
// 成功响应的构建器
public static <T> ApiResponse<T> success(T data, String requestId, long processingTime) {
return new ApiResponse<>(
true,
data,
null,
new Metadata(requestId, processingTime, "1.0")
);
}
// 错误响应的构建器
public static <T> ApiResponse<T> error(String code, String message, String requestId) {
return new ApiResponse<>(
false,
null,
new ErrorInfo(code, message, System.currentTimeMillis()),
new Metadata(requestId, 0, "1.0")
);
}
}
3.3 Record在函数式编程中的应用
java
// 函数式数据管道
public class DataProcessor {
public record User(String id, String name, int age, String department) {}
public record Department(String name, int budget, String location) {}
public record Report(String departmentName, long userCount, double averageAge) {}
public List<Report> generateDepartmentReport(
List<User> users,
List<Department> departments) {
return users.stream()
.collect(Collectors.groupingBy(User::department))
.entrySet().stream()
.map(entry -> {
String deptName = entry.getKey();
List<User> deptUsers = entry.getValue();
double avgAge = deptUsers.stream()
.mapToInt(User::age)
.average()
.orElse(0.0);
return new Report(deptName, deptUsers.size(), avgAge);
})
.sorted(Comparator.comparing(Report::departmentName))
.collect(Collectors.toList());
}
}
四、综合实战:类型安全的状态机
让我们通过一个实际项目来综合运用所学的特性:构建一个类型安全的订单处理状态机。
4.1 状态机设计
java
// 使用密封接口定义状态
public sealed interface OrderState
permits OrderState.Created, OrderState.Paid, OrderState.Shipped,
OrderState.Delivered, OrderState.Cancelled {
// 状态数据使用Record
record Created(String orderId, LocalDateTime createdAt, BigDecimal amount)
implements OrderState {}
record Paid(String orderId, LocalDateTime paidAt, BigDecimal amount,
String paymentId, PaymentMethod method)
implements OrderState {}
record Shipped(String orderId, LocalDateTime shippedAt, BigDecimal amount,
String trackingNumber, Address shippingAddress)
implements OrderState {}
record Delivered(String orderId, LocalDateTime deliveredAt, BigDecimal amount,
String signature)
implements OrderState {}
record Cancelled(String orderId, LocalDateTime cancelledAt, String reason)
implements OrderState {}
}
// 支持的数据类型
public record PaymentMethod(String type, String details) {}
public record Address(String street, String city, String country, String postalCode) {}
// 状态转换事件
public sealed interface OrderEvent
permits OrderEvent.PaymentReceived, OrderEvent.ShipmentDispatched,
OrderEvent.DeliveryConfirmed, OrderEvent.CancellationRequested {
record PaymentReceived(String paymentId, PaymentMethod method) implements OrderEvent {}
record ShipmentDispatched(String trackingNumber, Address address) implements OrderEvent {}
record DeliveryConfirmed(String signature) implements OrderEvent {}
record CancellationRequested(String reason) implements OrderEvent {}
}
4.2 状态机实现
java
public class OrderStateMachine {
// 状态转换结果
public sealed interface TransitionResult
permits TransitionResult.Success, TransitionResult.Failure {
record Success(OrderState newState) implements TransitionResult {}
record Failure(String reason, OrderState currentState) implements TransitionResult {}
}
// 核心转换逻辑:使用模式匹配确保类型安全
public TransitionResult transition(OrderState currentState, OrderEvent event) {
return switch (currentState) {
// Created状态的转换
case OrderState.Created(var orderId, var createdAt, var amount) ->
switch (event) {
case OrderEvent.PaymentReceived(var paymentId, var method) ->
new TransitionResult.Success(
new OrderState.Paid(orderId, LocalDateTime.now(),
amount, paymentId, method)
);
case OrderEvent.CancellationRequested(var reason) ->
new TransitionResult.Success(
new OrderState.Cancelled(orderId, LocalDateTime.now(), reason)
);
default -> new TransitionResult.Failure(
"Invalid transition from Created with event: " + event,
currentState
);
};
// Paid状态的转换
case OrderState.Paid(var orderId, var paidAt, var amount, var paymentId, var method) ->
switch (event) {
case OrderEvent.ShipmentDispatched(var trackingNumber, var address) ->
new TransitionResult.Success(
new OrderState.Shipped(orderId, LocalDateTime.now(),
amount, trackingNumber, address)
);
case OrderEvent.CancellationRequested(var reason) ->
new TransitionResult.Success(
new OrderState.Cancelled(orderId, LocalDateTime.now(), reason)
);
default -> new TransitionResult.Failure(
"Invalid transition from Paid with event: " + event,
currentState
);
};
// Shipped状态的转换
case OrderState.Shipped(var orderId, var shippedAt, var amount,
var trackingNumber, var address) ->
switch (event) {
case OrderEvent.DeliveryConfirmed(var signature) ->
new TransitionResult.Success(
new OrderState.Delivered(orderId, LocalDateTime.now(),
amount, signature)
);
default -> new TransitionResult.Failure(
"Invalid transition from Shipped with event: " + event,
currentState
);
};
// 终态不允许转换
case OrderState.Delivered(var orderId, var deliveredAt, var amount, var signature) ->
new TransitionResult.Failure(
"Order already delivered, no further transitions allowed",
currentState
);
case OrderState.Cancelled(var orderId, var cancelledAt, var reason) ->
new TransitionResult.Failure(
"Order already cancelled, no further transitions allowed",
currentState
);
};
}
// 状态查询方法
public boolean canCancel(OrderState state) {
return switch (state) {
case OrderState.Created(var orderId, var createdAt, var amount),
OrderState.Paid(var orderId2, var paidAt, var amount2, var paymentId, var method) ->
true;
case OrderState.Shipped(var orderId3, var shippedAt, var amount3,
var trackingNumber, var address),
OrderState.Delivered(var orderId4, var deliveredAt, var amount4, var signature),
OrderState.Cancelled(var orderId5, var cancelledAt, var reason) ->
false;
};
}
public String getStatusDescription(OrderState state) {
return switch (state) {
case OrderState.Created(var orderId, var createdAt, var amount) ->
String.format("Order %s created at %s for $%.2f",
orderId, createdAt, amount);
case OrderState.Paid(var orderId, var paidAt, var amount, var paymentId, var method) ->
String.format("Order %s paid at %s for $%.2f via %s",
orderId, paidAt, amount, method.type());
case OrderState.Shipped(var orderId, var shippedAt, var amount,
var trackingNumber, var address) ->
String.format("Order %s shipped at %s to %s, tracking: %s",
orderId, shippedAt, address.city(), trackingNumber);
case OrderState.Delivered(var orderId, var deliveredAt, var amount, var signature) ->
String.format("Order %s delivered at %s, signed by: %s",
orderId, deliveredAt, signature);
case OrderState.Cancelled(var orderId, var cancelledAt, var reason) ->
String.format("Order %s cancelled at %s, reason: %s",
orderId, cancelledAt, reason);
};
}
}
4.3 状态机使用示例
java
public class OrderProcessor {
private final OrderStateMachine stateMachine = new OrderStateMachine();
private final Map<String, OrderState> orders = new ConcurrentHashMap<>();
// 创建订单
public String createOrder(BigDecimal amount) {
String orderId = UUID.randomUUID().toString();
OrderState initialState = new OrderState.Created(
orderId, LocalDateTime.now(), amount
);
orders.put(orderId, initialState);
return orderId;
}
// 处理事件
public ProcessingResult processEvent(String orderId, OrderEvent event) {
OrderState currentState = orders.get(orderId);
if (currentState == null) {
return new ProcessingResult.Failure("Order not found: " + orderId);
}
return switch (stateMachine.transition(currentState, event)) {
case OrderStateMachine.TransitionResult.Success(var newState) -> {
orders.put(orderId, newState);
yield new ProcessingResult.Success(
stateMachine.getStatusDescription(newState)
);
}
case OrderStateMachine.TransitionResult.Failure(var reason, var state) ->
new ProcessingResult.Failure(reason);
};
}
// 处理结果
public sealed interface ProcessingResult
permits ProcessingResult.Success, ProcessingResult.Failure {
record Success(String message) implements ProcessingResult {}
record Failure(String error) implements ProcessingResult {}
}
// 查询订单状态
public Optional<String> getOrderStatus(String orderId) {
return Optional.ofNullable(orders.get(orderId))
.map(stateMachine::getStatusDescription);
}
// 获取可执行的操作
public List<String> getAvailableActions(String orderId) {
OrderState state = orders.get(orderId);
if (state == null) {
return List.of();
}
return switch (state) {
case OrderState.Created(var orderId2, var createdAt, var amount) ->
List.of("pay", "cancel");
case OrderState.Paid(var orderId3, var paidAt, var amount2, var paymentId, var method) ->
List.of("ship", "cancel");
case OrderState.Shipped(var orderId4, var shippedAt, var amount3,
var trackingNumber, var address) ->
List.of("confirm-delivery");
case OrderState.Delivered(var orderId5, var deliveredAt, var amount4, var signature),
OrderState.Cancelled(var orderId6, var cancelledAt, var reason) ->
List.of(); // 终态,无可用操作
};
}
}
4.4 完整的测试用例
java
public class OrderStateMachineTest {
@Test
public void testCompleteOrderFlow() {
OrderProcessor processor = new OrderProcessor();
// 1. 创建订单
String orderId = processor.createOrder(new BigDecimal("99.99"));
assertThat(processor.getAvailableActions(orderId))
.containsExactly("pay", "cancel");
// 2. 支付订单
var paymentEvent = new OrderEvent.PaymentReceived(
"payment-123",
new PaymentMethod("CREDIT_CARD", "****1234")
);
var result = processor.processEvent(orderId, paymentEvent);
assertThat(result).isInstanceOf(OrderProcessor.ProcessingResult.Success.class);
assertThat(processor.getAvailableActions(orderId))
.containsExactly("ship", "cancel");
// 3. 发货
var shipmentEvent = new OrderEvent.ShipmentDispatched(
"TRACK123456",
new Address("123 Main St", "Springfield", "USA", "12345")
);
result = processor.processEvent(orderId, shipmentEvent);
assertThat(result).isInstanceOf(OrderProcessor.ProcessingResult.Success.class);
assertThat(processor.getAvailableActions(orderId))
.containsExactly("confirm-delivery");
// 4. 确认送达
var deliveryEvent = new OrderEvent.DeliveryConfirmed("John Doe");
result = processor.processEvent(orderId, deliveryEvent);
assertThat(result).isInstanceOf(OrderProcessor.ProcessingResult.Success.class);
assertThat(processor.getAvailableActions(orderId)).isEmpty();
// 5. 验证最终状态
String status = processor.getOrderStatus(orderId).orElse("");
assertThat(status).contains("delivered");
assertThat(status).contains("John Doe");
}
@Test
public void testInvalidTransitions() {
OrderProcessor processor = new OrderProcessor();
String orderId = processor.createOrder(new BigDecimal("50.00"));
// 尝试无效的状态转换
var deliveryEvent = new OrderEvent.DeliveryConfirmed("Invalid");
var result = processor.processEvent(orderId, deliveryEvent);
assertThat(result).isInstanceOf(OrderProcessor.ProcessingResult.Failure.class);
// 验证状态未改变
assertThat(processor.getAvailableActions(orderId))
.containsExactly("pay", "cancel");
}
}
五、最佳实践与性能考量
5.1 密封类最佳实践
1. 合理使用密封层次
java
// ✅ 好的设计:清晰的继承层次
public sealed interface Vehicle permits Car, Motorcycle, Truck {
double getFuelEfficiency();
}
public sealed class Car implements Vehicle permits Sedan, SUV, Hatchback {
// 汽车的共同特性
}
public final class Sedan extends Car {
// 轿车特有实现
}
// ❌ 避免:过深的密封层次
public sealed interface A permits B {
// 过度设计
}
public sealed interface B extends A permits C {}
public sealed interface C extends B permits D {}
2. 与其他特性的组合
java
// ✅ 密封类 + Record + 模式匹配的完美组合
public sealed interface HttpResponse
permits HttpResponse.Success, HttpResponse.Error {
record Success(int statusCode, String body, Map<String, String> headers)
implements HttpResponse {}
record Error(int statusCode, String message, Throwable cause)
implements HttpResponse {}
// 流畅的处理方式
default <T> T handle(
Function<Success, T> onSuccess,
Function<Error, T> onError) {
return switch (this) {
case Success success -> onSuccess.apply(success);
case Error error -> onError.apply(error);
};
}
}
5.2 Switch模式匹配最佳实践
1. 穷尽性检查
java
// ✅ 利用密封类的穷尽性
public double calculateDiscount(CustomerType type) {
return switch (type) {
case CustomerType.Regular regular -> 0.05;
case CustomerType.Premium premium -> 0.10;
case CustomerType.VIP vip -> 0.15;
// 编译器确保所有情况都被覆盖
};
}
// ✅ 非密封类型需要default
public String formatValue(Object value) {
return switch (value) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case Double d -> "Double: " + d;
default -> "Other: " + value.toString();
};
}
2. 性能优化技巧
java
// ✅ 将常见情况放在前面
public String processRequest(RequestType type) {
return switch (type) {
case GET -> handleGet(); // 最常见
case POST -> handlePost(); // 次常见
case PUT -> handlePut(); // 较少见
case DELETE -> handleDelete(); // 最少见
};
}
// ✅ 使用守卫条件优化复杂逻辑
public int calculateShipping(Package pkg) {
return switch (pkg) {
case Package p when p.weight() < 1 -> 5;
case Package p when p.weight() < 5 -> 10;
case Package p when p.weight() < 10 -> 20;
case Package p -> 30;
};
}
5.3 Record类最佳实践
1. 数据验证策略
java
// ✅ 在紧凑构造器中进行验证
public record Email(String value) {
public Email {
Objects.requireNonNull(value, "Email cannot be null");
if (!value.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
throw new IllegalArgumentException("Invalid email format: " + value);
}
value = value.toLowerCase(); // 标准化
}
// 提供便利的工厂方法
public static Email of(String value) {
return new Email(value);
}
public String domain() {
return value.substring(value.indexOf('@') + 1);
}
}
2. 与集合框架的集成
java
// ✅ Record作为Map的键
public record PersonId(String type, String value) {
// 自动实现的equals和hashCode确保Map正确工作
}
Map<PersonId, Person> personRegistry = new HashMap<>();
personRegistry.put(new PersonId("SSN", "123-45-6789"), person);
// ✅ Record的自然排序
public record Score(String player, int points) implements Comparable<Score> {
@Override
public int compareTo(Score other) {
return Integer.compare(other.points, this.points); // 降序
}
}
List<Score> scores = List.of(
new Score("Alice", 100),
new Score("Bob", 150),
new Score("Charlie", 120)
);
Collections.sort(scores); // 自动按分数降序排列
5.4 性能分析和优化
1. 内存使用分析
java
// 使用JOL (Java Object Layout) 分析内存布局
public class MemoryAnalysis {
record CompactPerson(String name, int age) {}
static class RegularPerson {
private final String name;
private final int age;
// 构造器、getter、equals、hashCode等
}
public static void analyzeMemoryUsage() {
// Record通常更加内存高效
System.out.println("CompactPerson: " +
ClassLayout.parseClass(CompactPerson.class).toPrintable());
System.out.println("RegularPerson: " +
ClassLayout.parseClass(RegularPerson.class).toPrintable());
}
}
2. 运行时性能测试
java
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class PerformanceBenchmark {
@Benchmark
public String switchExpression(BenchmarkState state) {
return switch (state.shape) {
case Circle c -> "Circle: " + c.radius();
case Rectangle r -> "Rectangle: " + r.width() + "x" + r.height();
case Triangle t -> "Triangle: " + t.base() + "," + t.height();
};
}
@Benchmark
public String traditionalIfElse(BenchmarkState state) {
if (state.shape instanceof Circle c) {
return "Circle: " + c.radius();
} else if (state.shape instanceof Rectangle r) {
return "Rectangle: " + r.width() + "x" + r.height();
} else if (state.shape instanceof Triangle t) {
return "Triangle: " + t.base() + "," + t.height();
}
return "Unknown";
}
@State(Scope.Benchmark)
public static class BenchmarkState {
Shape shape = new Circle(5.0);
}
}
5.5 迁移指南
从传统代码迁移到现代特性
java
// 迁移前:传统继承体系
abstract class PaymentMethod {
abstract boolean process(double amount);
}
class CreditCard extends PaymentMethod {
private String number;
private String holder;
// 大量样板代码...
boolean process(double amount) {
return processCreditCard(amount);
}
}
// 迁移后:现代化设计
public sealed interface PaymentMethod
permits PaymentMethod.CreditCard, PaymentMethod.DebitCard, PaymentMethod.DigitalWallet {
record CreditCard(String number, String holder, String cvv) implements PaymentMethod {}
record DebitCard(String number, String pin) implements PaymentMethod {}
record DigitalWallet(String provider, String accountId) implements PaymentMethod {}
default boolean process(double amount) {
return switch (this) {
case CreditCard(var number, var holder, var cvv) ->
processCreditCard(amount, number, cvv);
case DebitCard(var number, var pin) ->
processDebitCard(amount, number, pin);
case DigitalWallet(var provider, var accountId) ->
processDigitalWallet(amount, provider, accountId);
};
}
private boolean processCreditCard(double amount, String number, String cvv) {
// 信用卡处理逻辑
return true;
}
private boolean processDebitCard(double amount, String number, String pin) {
// 借记卡处理逻辑
return true;
}
private boolean processDigitalWallet(double amount, String provider, String accountId) {
// 数字钱包处理逻辑
return true;
}
}
结语
核心收获总结
通过本期深入学习,我们掌握了JDK 17三大核心语言特性:
- 密封类:实现精确的类型控制,构建安全的继承层次
- Switch模式匹配:简化条件逻辑,提升代码表达力
- Record类型:现代化的数据建模,减少样板代码
这些特性的组合使用,让Java代码变得更加:
- 简洁优雅:减少冗余代码,提高可读性
- 类型安全:编译时检查,减少运行时错误
- 表达力强:更贴近问题域的自然表达
- 维护性好:清晰的结构,易于理解和修改
下期预告
第三期:JDK 17 性能优化与系统增强详解
下期我们将深入探讨JDK 17在性能方面的重大突破:
🚀 重点内容:
- ZGC垃圾收集器:超低延迟的GC革命
- 向量API:SIMD指令的Java实现
- 外部函数接口:高效的本地代码调用
- 新的数学函数:精确计算与性能优化
- 并发增强:更强大的并行处理能力
🎯 实战项目:
- 构建高性能数据处理管道
- 实现零拷贝的网络通信
- 优化计算密集型应用