JDK 17 实战系列(第2期):核心语言特性深度解析

引言

在第一期的全面概览中,我们了解了JDK 17作为LTS版本的重要意义和完整的特性图谱。从本期开始,我们将深入每个技术领域的细节。第二期聚焦于JDK 17最引人注目的语言特性革新。

这些语言特性不仅仅是语法糖,而是Java语言设计哲学的重要演进:

  • 密封类(Sealed Classes):实现精确的类型控制和安全的继承层次
  • Switch模式匹配:带来函数式编程的优雅表达
  • Record类型进阶:现代化的数据建模方案

本期将通过实际案例、最佳实践和设计原理的深度分析,帮助您完全掌握这些特性的精髓。

目录

  1. 密封类完全指南
  2. Switch模式匹配详解
  3. Record类型进阶应用
  4. 综合实战:类型安全的状态机
  5. 最佳实践与性能考量

一、密封类完全指南

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三大核心语言特性:

  1. 密封类:实现精确的类型控制,构建安全的继承层次
  2. Switch模式匹配:简化条件逻辑,提升代码表达力
  3. Record类型:现代化的数据建模,减少样板代码

这些特性的组合使用,让Java代码变得更加:

  • 简洁优雅:减少冗余代码,提高可读性
  • 类型安全:编译时检查,减少运行时错误
  • 表达力强:更贴近问题域的自然表达
  • 维护性好:清晰的结构,易于理解和修改

下期预告

第三期:JDK 17 性能优化与系统增强详解

下期我们将深入探讨JDK 17在性能方面的重大突破:

🚀 重点内容

  • ZGC垃圾收集器:超低延迟的GC革命
  • 向量API:SIMD指令的Java实现
  • 外部函数接口:高效的本地代码调用
  • 新的数学函数:精确计算与性能优化
  • 并发增强:更强大的并行处理能力

🎯 实战项目

  • 构建高性能数据处理管道
  • 实现零拷贝的网络通信
  • 优化计算密集型应用

参考资料

  1. JEP 409: Sealed Classes
  2. JEP 406: Pattern Matching for switch (Preview)
  3. JEP 395: Records
  4. Java Language Specification - Sealed Classes
  5. OpenJDK Pattern Matching Documentation
相关推荐
半桔10 分钟前
【STL源码剖析】从源码看 vector:底层扩容逻辑与内存复用机制
java·开发语言·c++·容器·stl
洛卡卡了22 分钟前
面试官问限流降级,我项目根本没做过,咋办?
后端·面试·架构
慕y27422 分钟前
Java学习第一百零九部分——Jenkins(一)
java·学习·jenkins
ezl1fe41 分钟前
RAG 每日一技(十四):化繁为简,统揽全局——用LangChain构建高级RAG流程
人工智能·后端·算法
悟能不能悟1 小时前
cdn是什么
java
amazingCompass1 小时前
Java 开发必备技能:深入理解与实战 IntelliJ IDEA 中的 VM Options
后端
爱科研的瞌睡虫1 小时前
C++线程中 detach() 和 join() 的区别
java·c++·算法
每天的每一天1 小时前
分布式文件系统05-生产级中间件的Java网络通信技术深度优化
java·开发语言·中间件
落叶的悲哀1 小时前
面试问题11
java·数据库·面试
欧的曼1 小时前
cygwin+php教程(swoole扩展+redis扩展)
开发语言·redis·后端·mysql·nginx·php·swoole