Java 17新特性深度解读:Records、Sealed Classes与Pattern Matching

引言

Java 17作为继Java 11之后的第二个长期支持(LTS)版本,标志着Java语言在现代化道路上的重要里程碑。本文将深入探讨Java 17中三个最具革命性的特性:Records、Sealed Classes和Pattern Matching,分析它们如何重塑Java的编程范式,并提供实际应用中的最佳实践。

目录

  1. Records:重新定义数据载体
  2. Sealed Classes:精确控制类型层次
  3. Pattern Matching:函数式编程的桥梁
  4. 三大特性的协同应用
  5. 性能分析与最佳实践
  6. 迁移指南与实战案例

Records:重新定义数据载体

深入理解Records的设计哲学

Records的引入不仅仅是为了减少样板代码,更重要的是体现了Java对不可变性和函数式编程的拥抱。Records本质上是一种特殊的类,专门用于建模不可变数据。

// 传统的数据类需要大量样板代码
public final class TraditionalPerson {
    private final String name;
    private final int age;
    private final String email;
    
    public TraditionalPerson(String name, int age, String email) {
        this.name = Objects.requireNonNull(name);
        this.age = age;
        this.email = Objects.requireNonNull(email);
    }
    
    // 大量的getter、equals、hashCode、toString方法...
}

// 使用Record,一行代码搞定
public record Person(String name, int age, String email) {
    // 可选:添加验证逻辑
    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");
    }
}

Records的高级特性

1. 紧凑构造函数(Compact Constructor)

Records引入了紧凑构造函数的概念,允许在不重复参数列表的情况下添加验证逻辑:

public record BankAccount(String accountNumber, BigDecimal balance, Currency currency) {
    public BankAccount {
        // 验证逻辑
        if (accountNumber == null || accountNumber.trim().isEmpty()) {
            throw new IllegalArgumentException("Account number cannot be empty");
        }
        if (balance.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("Balance cannot be negative");
        }
        Objects.requireNonNull(currency, "Currency cannot be null");
        
        // 数据标准化
        accountNumber = accountNumber.trim().toUpperCase();
    }
    
    // 静态工厂方法
    public static BankAccount createSavingsAccount(String accountNumber, BigDecimal initialDeposit) {
        return new BankAccount(accountNumber, initialDeposit, Currency.getInstance("USD"));
    }
    
    // 业务方法
    public BankAccount deposit(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Deposit amount must be positive");
        }
        return new BankAccount(accountNumber, balance.add(amount), currency);
    }
    
    public BankAccount withdraw(BigDecimal amount) {
        if (amount.compareTo(balance) > 0) {
            throw new IllegalArgumentException("Insufficient funds");
        }
        return new BankAccount(accountNumber, balance.subtract(amount), currency);
    }
}
2. Records与泛型的结合

Records完全支持泛型,可以创建类型安全的数据容器:

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 <U> Result<U, E> map(Function<T, U> mapper) {
        return isSuccess ? success(mapper.apply(value)) : failure(error);
    }
    
    public <F> Result<T, F> mapError(Function<E, F> mapper) {
        return isSuccess ? success(value) : failure(mapper.apply(error));
    }
    
    public T orElse(T defaultValue) {
        return isSuccess ? value : defaultValue;
    }
    
    public T orElseThrow(Function<E, RuntimeException> exceptionMapper) {
        if (isSuccess) return value;
        throw exceptionMapper.apply(error);
    }
}

// 使用示例
public class UserService {
    public Result<User, String> findUserById(Long id) {
        try {
            User user = userRepository.findById(id);
            return user != null ? Result.success(user) : Result.failure("User not found");
        } catch (Exception e) {
            return Result.failure("Database error: " + e.getMessage());
        }
    }
    
    public Result<String, String> processUser(Long userId) {
        return findUserById(userId)
            .map(user -> "Processed user: " + user.name())
            .mapError(error -> "Failed to process user: " + error);
    }
}

Sealed Classes:精确控制类型层次

Sealed Classes的设计动机

Sealed Classes解决了Java长期以来的一个问题:无法精确控制类型层次结构。在传统Java中,一旦声明了一个public接口或抽象类,任何人都可以实现或继承它,这在某些场景下是不希望的。

深入理解Sealed Classes

// 定义一个密封的表达式类型层次
public sealed interface Expression 
    permits Constant, Addition, Multiplication, Variable {
}

public record Constant(double value) implements Expression {}

public record Variable(String name) implements Expression {}

public record Addition(Expression left, Expression right) implements Expression {}

public record Multiplication(Expression left, Expression right) implements Expression {}

// 表达式求值器
public class ExpressionEvaluator {
    private final Map<String, Double> variables;
    
    public ExpressionEvaluator(Map<String, Double> variables) {
        this.variables = new HashMap<>(variables);
    }
    
    public double evaluate(Expression expr) {
        return switch (expr) {
            case Constant(var value) -> value;
            case Variable(var name) -> variables.getOrDefault(name, 0.0);
            case Addition(var left, var right) -> evaluate(left) + evaluate(right);
            case Multiplication(var left, var right) -> evaluate(left) * evaluate(right);
            // 编译器保证穷尽性,无需default分支
        };
    }
    
    // 表达式简化
    public Expression simplify(Expression expr) {
        return switch (expr) {
            case Constant c -> c;
            case Variable v -> v;
            case Addition(Constant(0.0), var right) -> simplify(right);
            case Addition(var left, Constant(0.0)) -> simplify(left);
            case Addition(Constant(var a), Constant(var b)) -> new Constant(a + b);
            case Addition(var left, var right) -> 
                new Addition(simplify(left), simplify(right));
            case Multiplication(Constant(0.0), var right) -> new Constant(0.0);
            case Multiplication(var left, Constant(0.0)) -> new Constant(0.0);
            case Multiplication(Constant(1.0), var right) -> simplify(right);
            case Multiplication(var left, Constant(1.0)) -> simplify(left);
            case Multiplication(Constant(var a), Constant(var b)) -> new Constant(a * b);
            case Multiplication(var left, var right) -> 
                new Multiplication(simplify(left), simplify(right));
        };
    }
}

Sealed Classes的继承策略

Sealed Classes提供了三种继承策略:

// 1. final - 终止继承链
public final class Circle implements Shape {
    private final double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    public double area() {
        return Math.PI * radius * radius;
    }
}

// 2. sealed - 继续密封继承
public sealed class Polygon implements Shape 
    permits Triangle, Rectangle, Pentagon {
    protected final List<Point> vertices;
    
    protected Polygon(List<Point> vertices) {
        this.vertices = List.copyOf(vertices);
    }
}

public final class Triangle extends Polygon {
    public Triangle(Point a, Point b, Point c) {
        super(List.of(a, b, c));
    }
    
    public double area() {
        // 使用海伦公式计算三角形面积
        Point a = vertices.get(0), b = vertices.get(1), c = vertices.get(2);
        double sideA = distance(b, c);
        double sideB = distance(a, c);
        double sideC = distance(a, b);
        double s = (sideA + sideB + sideC) / 2;
        return Math.sqrt(s * (s - sideA) * (s - sideB) * (s - sideC));
    }
    
    private double distance(Point p1, Point p2) {
        return Math.sqrt(Math.pow(p2.x() - p1.x(), 2) + Math.pow(p2.y() - p1.y(), 2));
    }
}

// 3. non-sealed - 开放继承
public non-sealed class Rectangle extends Polygon {
    public Rectangle(double width, double height) {
        super(List.of(
            new Point(0, 0),
            new Point(width, 0),
            new Point(width, height),
            new Point(0, height)
        ));
    }
    
    public double area() {
        Point p1 = vertices.get(0), p2 = vertices.get(1), p3 = vertices.get(2);
        double width = Math.abs(p2.x() - p1.x());
        double height = Math.abs(p3.y() - p2.y());
        return width * height;
    }
}

// Rectangle是non-sealed的,所以可以被任意类继承
public class Square extends Rectangle {
    public Square(double side) {
        super(side, side);
    }
}

Pattern Matching:函数式编程的桥梁

Pattern Matching的演进历程

Pattern Matching在Java中的引入是渐进式的:

  • Java 14: instanceof的模式匹配(预览)
  • Java 16: instanceof的模式匹配(正式)
  • Java 17: switch的模式匹配(预览)
  • Java 21: switch的模式匹配(正式)

高级Pattern Matching技术

// 复杂的模式匹配示例
public class JsonProcessor {
    
    public sealed interface JsonValue 
        permits JsonNull, JsonBoolean, JsonNumber, JsonString, JsonArray, JsonObject {}
    
    public record JsonNull() implements JsonValue {}
    public record JsonBoolean(boolean value) implements JsonValue {}
    public record JsonNumber(double value) implements JsonValue {}
    public record JsonString(String value) implements JsonValue {}
    public record JsonArray(List<JsonValue> elements) implements JsonValue {}
    public record JsonObject(Map<String, JsonValue> fields) implements JsonValue {}
    
    // 使用模式匹配进行JSON处理
    public String formatJson(JsonValue json, int indent) {
        return switch (json) {
            case JsonNull() -> "null";
            case JsonBoolean(var value) -> String.valueOf(value);
            case JsonNumber(var value) -> formatNumber(value);
            case JsonString(var value) -> "\"" + escapeString(value) + "\"";
            case JsonArray(var elements) -> formatArray(elements, indent);
            case JsonObject(var fields) -> formatObject(fields, indent);
        };
    }
    
    private String formatArray(List<JsonValue> elements, int indent) {
        if (elements.isEmpty()) return "[]";
        
        String indentStr = " ".repeat(indent);
        String nextIndentStr = " ".repeat(indent + 2);
        
        return "[\n" + 
               elements.stream()
                   .map(elem -> nextIndentStr + formatJson(elem, indent + 2))
                   .collect(Collectors.joining(",\n")) +
               "\n" + indentStr + "]";
    }
    
    private String formatObject(Map<String, JsonValue> fields, int indent) {
        if (fields.isEmpty()) return "{}";
        
        String indentStr = " ".repeat(indent);
        String nextIndentStr = " ".repeat(indent + 2);
        
        return "{\n" +
               fields.entrySet().stream()
                   .map(entry -> nextIndentStr + "\"" + escapeString(entry.getKey()) + 
                                "\": " + formatJson(entry.getValue(), indent + 2))
                   .collect(Collectors.joining(",\n")) +
               "\n" + indentStr + "}";
    }
    
    // 类型安全的JSON查询
    public Optional<JsonValue> query(JsonValue json, String path) {
        String[] parts = path.split("\\.");
        JsonValue current = json;
        
        for (String part : parts) {
            current = switch (current) {
                case JsonObject(var fields) -> fields.get(part);
                case JsonArray(var elements) -> {
                    try {
                        int index = Integer.parseInt(part);
                        yield index >= 0 && index < elements.size() ? 
                              elements.get(index) : null;
                    } catch (NumberFormatException e) {
                        yield null;
                    }
                }
                default -> null;
            };
            
            if (current == null) return Optional.empty();
        }
        
        return Optional.of(current);
    }
    
    private String formatNumber(double value) {
        return value == (long) value ? String.valueOf((long) value) : String.valueOf(value);
    }
    
    private String escapeString(String str) {
        return str.replace("\\", "\\\\")
                  .replace("\"", "\\\"")
                  .replace("\n", "\\n")
                  .replace("\r", "\\r")
                  .replace("\t", "\\t");
    }
}

Guard条件与复杂模式

public class AdvancedPatternMatching {
    
    public sealed interface Animal permits Dog, Cat, Bird {}
    public record Dog(String name, int age, String breed) implements Animal {}
    public record Cat(String name, int age, boolean isIndoor) implements Animal {}
    public record Bird(String name, int age, boolean canFly) implements Animal {}
    
    // 使用guard条件的模式匹配
    public String describeAnimal(Animal animal) {
        return switch (animal) {
            case Dog(var name, var age, var breed) when age < 1 -> 
                "Puppy " + name + " is a young " + breed;
            case Dog(var name, var age, var breed) when age > 10 -> 
                "Senior dog " + name + " is an old " + breed;
            case Dog(var name, var age, var breed) -> 
                name + " is a " + age + "-year-old " + breed;
                
            case Cat(var name, var age, true) when age < 1 -> 
                "Kitten " + name + " is an indoor cat";
            case Cat(var name, var age, false) when age > 12 -> 
                "Senior outdoor cat " + name;
            case Cat(var name, var age, var isIndoor) -> 
                name + " is a " + age + "-year-old " + (isIndoor ? "indoor" : "outdoor") + " cat";
                
            case Bird(var name, var age, true) -> 
                "Flying bird " + name + " (" + age + " years old)";
            case Bird(var name, var age, false) -> 
                "Flightless bird " + name + " (" + age + " years old)";
        };
    }
    
    // 嵌套模式匹配
    public record Owner(String name, Animal pet) {}
    
    public String describePetOwner(Owner owner) {
        return switch (owner) {
            case Owner(var ownerName, Dog(var petName, var age, "Golden Retriever")) -> 
                ownerName + " owns a Golden Retriever named " + petName;
            case Owner(var ownerName, Cat(var petName, var age, true)) when age < 2 -> 
                ownerName + " has a young indoor kitten named " + petName;
            case Owner(var ownerName, var pet) -> 
                ownerName + " owns a pet: " + describeAnimal(pet);
        };
    }
}

三大特性的协同应用

构建类型安全的状态机

Records、Sealed Classes和Pattern Matching的结合使用可以创建强大的类型安全状态机:

public class OrderStateMachine {

    public sealed interface OrderState
        permits Pending, Confirmed, Shipped, Delivered, Cancelled {}

    public record Pending(LocalDateTime createdAt, BigDecimal amount) implements OrderState {}
    public record Confirmed(LocalDateTime createdAt, BigDecimal amount,
                           LocalDateTime confirmedAt, String paymentId) implements OrderState {}
    public record Shipped(LocalDateTime createdAt, BigDecimal amount,
                         LocalDateTime confirmedAt, String paymentId,
                         LocalDateTime shippedAt, String trackingNumber) implements OrderState {}
    public record Delivered(LocalDateTime createdAt, BigDecimal amount,
                           LocalDateTime confirmedAt, String paymentId,
                           LocalDateTime shippedAt, String trackingNumber,
                           LocalDateTime deliveredAt, String signature) implements OrderState {}
    public record Cancelled(LocalDateTime createdAt, BigDecimal amount,
                           LocalDateTime cancelledAt, String reason) implements OrderState {}

    public sealed interface OrderEvent
        permits ConfirmPayment, ShipOrder, DeliverOrder, CancelOrder {}

    public record ConfirmPayment(String paymentId) implements OrderEvent {}
    public record ShipOrder(String trackingNumber) implements OrderEvent {}
    public record DeliverOrder(String signature) implements OrderEvent {}
    public record CancelOrder(String reason) implements OrderEvent {}

    // 状态转换逻辑
    public Result<OrderState, String> transition(OrderState currentState, OrderEvent event) {
        return switch (currentState) {
            case Pending(var createdAt, var amount) -> switch (event) {
                case ConfirmPayment(var paymentId) -> Result.success(
                    new Confirmed(createdAt, amount, LocalDateTime.now(), paymentId));
                case CancelOrder(var reason) -> Result.success(
                    new Cancelled(createdAt, amount, LocalDateTime.now(), reason));
                default -> Result.failure("Invalid transition from Pending state");
            };

            case Confirmed(var createdAt, var amount, var confirmedAt, var paymentId) -> switch (event) {
                case ShipOrder(var trackingNumber) -> Result.success(
                    new Shipped(createdAt, amount, confirmedAt, paymentId,
                               LocalDateTime.now(), trackingNumber));
                case CancelOrder(var reason) -> Result.success(
                    new Cancelled(createdAt, amount, LocalDateTime.now(), reason));
                default -> Result.failure("Invalid transition from Confirmed state");
            };

            case Shipped(var createdAt, var amount, var confirmedAt, var paymentId,
                        var shippedAt, var trackingNumber) -> switch (event) {
                case DeliverOrder(var signature) -> Result.success(
                    new Delivered(createdAt, amount, confirmedAt, paymentId,
                                 shippedAt, trackingNumber, LocalDateTime.now(), signature));
                default -> Result.failure("Invalid transition from Shipped state");
            };

            case Delivered(var createdAt, var amount, var confirmedAt, var paymentId,
                          var shippedAt, var trackingNumber, var deliveredAt, var signature) ->
                Result.failure("Order already delivered - no further transitions allowed");

            case Cancelled(var createdAt, var amount, var cancelledAt, var reason) ->
                Result.failure("Order cancelled - no further transitions allowed");
        };
    }

    // 获取订单状态描述
    public String getStateDescription(OrderState state) {
        return switch (state) {
            case Pending(var createdAt, var amount) ->
                "Order pending (Created: %s, Amount: $%.2f)".formatted(createdAt, amount);
            case Confirmed(var createdAt, var amount, var confirmedAt, var paymentId) ->
                "Order confirmed (Payment: %s, Amount: $%.2f)".formatted(paymentId, amount);
            case Shipped(var createdAt, var amount, var confirmedAt, var paymentId,
                        var shippedAt, var trackingNumber) ->
                "Order shipped (Tracking: %s, Shipped: %s)".formatted(trackingNumber, shippedAt);
            case Delivered(var createdAt, var amount, var confirmedAt, var paymentId,
                          var shippedAt, var trackingNumber, var deliveredAt, var signature) ->
                "Order delivered (Delivered: %s, Signature: %s)".formatted(deliveredAt, signature);
            case Cancelled(var createdAt, var amount, var cancelledAt, var reason) ->
                "Order cancelled (Reason: %s, Cancelled: %s)".formatted(reason, cancelledAt);
        };
    }

    // 检查是否可以执行特定操作
    public boolean canExecuteEvent(OrderState state, OrderEvent event) {
        return transition(state, event).isSuccess();
    }
}

函数式编程风格的数据处理管道

public class DataProcessingPipeline {

    public sealed interface ProcessingStep<T, R>
        permits MapStep, FilterStep, FlatMapStep, ReduceStep {}

    public record MapStep<T, R>(Function<T, R> mapper) implements ProcessingStep<T, R> {}
    public record FilterStep<T>(Predicate<T> predicate) implements ProcessingStep<T, T> {}
    public record FlatMapStep<T, R>(Function<T, Stream<R>> mapper) implements ProcessingStep<T, R> {}
    public record ReduceStep<T>(T identity, BinaryOperator<T> accumulator) implements ProcessingStep<T, T> {}

    public sealed interface DataSource<T>
        permits ListSource, StreamSource, GeneratorSource {}

    public record ListSource<T>(List<T> data) implements DataSource<T> {}
    public record StreamSource<T>(Stream<T> stream) implements DataSource<T> {}
    public record GeneratorSource<T>(Supplier<T> generator, int count) implements DataSource<T> {}

    // 执行数据处理管道
    @SuppressWarnings("unchecked")
    public <T, R> Stream<R> execute(DataSource<T> source, List<ProcessingStep<?, ?>> steps) {
        Stream<?> currentStream = switch (source) {
            case ListSource<T>(var data) -> data.stream();
            case StreamSource<T>(var stream) -> stream;
            case GeneratorSource<T>(var generator, var count) ->
                Stream.generate(generator).limit(count);
        };

        for (ProcessingStep<?, ?> step : steps) {
            currentStream = switch (step) {
                case MapStep<?, ?>(var mapper) -> currentStream.map((Function<Object, Object>) mapper);
                case FilterStep<?>(var predicate) -> currentStream.filter((Predicate<Object>) predicate);
                case FlatMapStep<?, ?>(var mapper) -> currentStream.flatMap((Function<Object, Stream<Object>>) mapper);
                case ReduceStep<?>(var identity, var accumulator) ->
                    Stream.of(currentStream.reduce(identity, (BinaryOperator<Object>) accumulator));
            };
        }

        return (Stream<R>) currentStream;
    }

    // 构建器模式
    public static class PipelineBuilder<T> {
        private final DataSource<T> source;
        private final List<ProcessingStep<?, ?>> steps = new ArrayList<>();

        public PipelineBuilder(DataSource<T> source) {
            this.source = source;
        }

        public <R> PipelineBuilder<R> map(Function<T, R> mapper) {
            steps.add(new MapStep<>(mapper));
            return (PipelineBuilder<R>) this;
        }

        public PipelineBuilder<T> filter(Predicate<T> predicate) {
            steps.add(new FilterStep<>(predicate));
            return this;
        }

        public <R> PipelineBuilder<R> flatMap(Function<T, Stream<R>> mapper) {
            steps.add(new FlatMapStep<>(mapper));
            return (PipelineBuilder<R>) this;
        }

        public <R> Stream<R> execute() {
            return new DataProcessingPipeline().execute(source, steps);
        }
    }

    public static <T> PipelineBuilder<T> from(List<T> data) {
        return new PipelineBuilder<>(new ListSource<>(data));
    }

    public static <T> PipelineBuilder<T> from(Stream<T> stream) {
        return new PipelineBuilder<>(new StreamSource<>(stream));
    }

    public static <T> PipelineBuilder<T> generate(Supplier<T> generator, int count) {
        return new PipelineBuilder<>(new GeneratorSource<>(generator, count));
    }
}

// 使用示例
public class PipelineExample {
    public record Person(String name, int age, String department) {}

    public void demonstratePipeline() {
        List<Person> employees = List.of(
            new Person("Alice", 30, "Engineering"),
            new Person("Bob", 25, "Marketing"),
            new Person("Charlie", 35, "Engineering"),
            new Person("Diana", 28, "Sales")
        );

        List<String> engineerNames = DataProcessingPipeline
            .from(employees)
            .filter(person -> "Engineering".equals(person.department()))
            .map(Person::name)
            .execute()
            .toList();

        System.out.println("Engineers: " + engineerNames);
    }
}

性能分析与最佳实践

Records的性能特征

Records在性能方面有以下特点:

  1. 内存效率:Records生成的类结构紧凑,没有额外的开销
  2. 方法调用开销:访问器方法可能比直接字段访问略慢,但JIT编译器通常会优化这些调用
  3. 对象创建:由于不可变性,可能需要更频繁的对象创建
public class RecordsPerformanceAnalysis {

    // 性能测试:Records vs 传统类
    @Benchmark
    public void traditionalClassCreation() {
        for (int i = 0; i < 1000000; i++) {
            TraditionalPoint point = new TraditionalPoint(i, i * 2);
        }
    }

    @Benchmark
    public void recordCreation() {
        for (int i = 0; i < 1000000; i++) {
            Point point = new Point(i, i * 2);
        }
    }

    // 传统类
    public static final class TraditionalPoint {
        private final int x, y;

        public TraditionalPoint(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() { return x; }
        public int getY() { return y; }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (!(obj instanceof TraditionalPoint other)) return false;
            return x == other.x && y == other.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }

    // Record类
    public record Point(int x, int y) {}

    // 性能优化建议
    public record OptimizedPerson(String name, int age) {
        // 缓存hashCode以提高性能
        private static final Map<OptimizedPerson, Integer> hashCodeCache =
            new ConcurrentHashMap<>();

        @Override
        public int hashCode() {
            return hashCodeCache.computeIfAbsent(this,
                person -> Objects.hash(person.name(), person.age()));
        }

        // 对于频繁使用的计算,可以添加缓存
        public String displayName() {
            return name + " (" + age + ")";
        }
    }
}

Sealed Classes的性能影响

Sealed Classes主要影响编译时性能和运行时的模式匹配效率:

public class SealedClassesPerformance {

    public sealed interface Operation permits Add, Subtract, Multiply, Divide {}

    public record Add(double a, double b) implements Operation {}
    public record Subtract(double a, double b) implements Operation {}
    public record Multiply(double a, double b) implements Operation {}
    public record Divide(double a, double b) implements Operation {}

    // 高效的模式匹配实现
    public double calculate(Operation op) {
        return switch (op) {
            case Add(var a, var b) -> a + b;
            case Subtract(var a, var b) -> a - b;
            case Multiply(var a, var b) -> a * b;
            case Divide(var a, var b) -> b != 0 ? a / b : Double.NaN;
        };
    }

    // 与传统多态方法的性能对比
    public sealed interface PolymorphicOperation permits PolyAdd, PolySubtract, PolyMultiply, PolyDivide {
        double execute();
    }

    public record PolyAdd(double a, double b) implements PolymorphicOperation {
        public double execute() { return a + b; }
    }

    public record PolySubtract(double a, double b) implements PolymorphicOperation {
        public double execute() { return a - b; }
    }

    public record PolyMultiply(double a, double b) implements PolymorphicOperation {
        public double execute() { return a * b; }
    }

    public record PolyDivide(double a, double b) implements PolymorphicOperation {
        public double execute() { return b != 0 ? a / b : Double.NaN; }
    }
}

最佳实践指南

1. Records使用最佳实践
public class RecordsBestPractices {

    // ✅ 好的实践:使用Records作为DTO
    public record UserDTO(Long id, String username, String email, LocalDateTime createdAt) {
        public UserDTO {
            Objects.requireNonNull(username, "Username cannot be null");
            Objects.requireNonNull(email, "Email cannot be null");
            if (username.trim().isEmpty()) {
                throw new IllegalArgumentException("Username cannot be empty");
            }
        }
    }

    // ✅ 好的实践:Records与Builder模式结合
    public record ComplexConfiguration(
        String host,
        int port,
        boolean ssl,
        Duration timeout,
        Map<String, String> properties
    ) {
        public ComplexConfiguration {
            Objects.requireNonNull(host);
            if (port <= 0 || port > 65535) {
                throw new IllegalArgumentException("Invalid port: " + port);
            }
            Objects.requireNonNull(timeout);
            properties = Map.copyOf(properties); // 防御性复制
        }

        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private String host = "localhost";
            private int port = 8080;
            private boolean ssl = false;
            private Duration timeout = Duration.ofSeconds(30);
            private Map<String, String> properties = new HashMap<>();

            public Builder host(String host) {
                this.host = host;
                return this;
            }

            public Builder port(int port) {
                this.port = port;
                return this;
            }

            public Builder ssl(boolean ssl) {
                this.ssl = ssl;
                return this;
            }

            public Builder timeout(Duration timeout) {
                this.timeout = timeout;
                return this;
            }

            public Builder property(String key, String value) {
                this.properties.put(key, value);
                return this;
            }

            public ComplexConfiguration build() {
                return new ComplexConfiguration(host, port, ssl, timeout, properties);
            }
        }
    }

    // ❌ 避免:Records包含可变对象而不进行防御性复制
    public record BadRecord(List<String> items) {} // 危险:外部可以修改list

    // ✅ 正确:进行防御性复制
    public record GoodRecord(List<String> items) {
        public GoodRecord {
            items = List.copyOf(items); // 创建不可变副本
        }
    }
}
2. Sealed Classes使用最佳实践
public class SealedClassesBestPractices {

    // ✅ 好的实践:使用Sealed Classes建模有限状态集
    public sealed interface PaymentMethod
        permits CreditCard, DebitCard, PayPal, BankTransfer {
    }

    public record CreditCard(String number, String holderName, YearMonth expiry)
        implements PaymentMethod {
        public CreditCard {
            Objects.requireNonNull(number);
            Objects.requireNonNull(holderName);
            Objects.requireNonNull(expiry);
            if (expiry.isBefore(YearMonth.now())) {
                throw new IllegalArgumentException("Card expired");
            }
        }
    }

    public record DebitCard(String number, String holderName, String pin)
        implements PaymentMethod {
        public DebitCard {
            Objects.requireNonNull(number);
            Objects.requireNonNull(holderName);
            Objects.requireNonNull(pin);
        }
    }

    public record PayPal(String email) implements PaymentMethod {
        public PayPal {
            Objects.requireNonNull(email);
            if (!email.contains("@")) {
                throw new IllegalArgumentException("Invalid email");
            }
        }
    }

    public record BankTransfer(String accountNumber, String routingNumber)
        implements PaymentMethod {
        public BankTransfer {
            Objects.requireNonNull(accountNumber);
            Objects.requireNonNull(routingNumber);
        }
    }

    // 类型安全的支付处理
    public class PaymentProcessor {
        public Result<String, String> processPayment(PaymentMethod method, BigDecimal amount) {
            return switch (method) {
                case CreditCard(var number, var holder, var expiry) ->
                    processCreditCard(number, holder, expiry, amount);
                case DebitCard(var number, var holder, var pin) ->
                    processDebitCard(number, holder, pin, amount);
                case PayPal(var email) ->
                    processPayPal(email, amount);
                case BankTransfer(var account, var routing) ->
                    processBankTransfer(account, routing, amount);
            };
        }

        private Result<String, String> processCreditCard(String number, String holder,
                                                        YearMonth expiry, BigDecimal amount) {
            // 信用卡处理逻辑
            return Result.success("Credit card payment processed: " + amount);
        }

        private Result<String, String> processDebitCard(String number, String holder,
                                                       String pin, BigDecimal amount) {
            // 借记卡处理逻辑
            return Result.success("Debit card payment processed: " + amount);
        }

        private Result<String, String> processPayPal(String email, BigDecimal amount) {
            // PayPal处理逻辑
            return Result.success("PayPal payment processed: " + amount);
        }

        private Result<String, String> processBankTransfer(String account, String routing,
                                                          BigDecimal amount) {
            // 银行转账处理逻辑
            return Result.success("Bank transfer processed: " + amount);
        }
    }
}

迁移指南与实战案例

从传统代码迁移到Java 17新特性

1. 识别迁移候选
// 迁移前:传统的数据类
public class LegacyUser {
    private final Long id;
    private final String username;
    private final String email;
    private final LocalDateTime createdAt;

    public LegacyUser(Long id, String username, String email, LocalDateTime createdAt) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.createdAt = createdAt;
    }

    // 大量的getter方法...
    public Long getId() { return id; }
    public String getUsername() { return username; }
    public String getEmail() { return email; }
    public LocalDateTime getCreatedAt() { return createdAt; }

    // equals、hashCode、toString方法...
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof LegacyUser that)) return false;
        return Objects.equals(id, that.id) &&
               Objects.equals(username, that.username) &&
               Objects.equals(email, that.email) &&
               Objects.equals(createdAt, that.createdAt);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, email, createdAt);
    }

    @Override
    public String toString() {
        return "LegacyUser{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", createdAt=" + createdAt +
                '}';
    }
}

// 迁移后:使用Record
public record User(Long id, String username, String email, LocalDateTime createdAt) {
    public User {
        Objects.requireNonNull(username, "Username cannot be null");
        Objects.requireNonNull(email, "Email cannot be null");
        Objects.requireNonNull(createdAt, "Created date cannot be null");

        if (username.trim().isEmpty()) {
            throw new IllegalArgumentException("Username cannot be empty");
        }

        if (!email.contains("@")) {
            throw new IllegalArgumentException("Invalid email format");
        }
    }

    // 可以添加业务方法
    public boolean isRecentlyCreated() {
        return createdAt.isAfter(LocalDateTime.now().minusDays(7));
    }

    public User withEmail(String newEmail) {
        return new User(id, username, newEmail, createdAt);
    }
}
2. 重构类型层次结构
// 迁移前:传统的多态设计
public abstract class LegacyShape {
    public abstract double area();
    public abstract double perimeter();
}

public class LegacyCircle extends LegacyShape {
    private final double radius;

    public LegacyCircle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }

    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }

    public double getRadius() { return radius; }
}

public class LegacyRectangle extends LegacyShape {
    private final double width;
    private final double height;

    public LegacyRectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }

    @Override
    public double perimeter() {
        return 2 * (width + height);
    }

    public double getWidth() { return width; }
    public double getHeight() { return height; }
}

// 传统的处理方式
public class LegacyShapeProcessor {
    public String describeShape(LegacyShape shape) {
        if (shape instanceof LegacyCircle circle) {
            return "Circle with radius " + circle.getRadius();
        } else if (shape instanceof LegacyRectangle rectangle) {
            return "Rectangle " + rectangle.getWidth() + "x" + rectangle.getHeight();
        } else {
            return "Unknown shape";
        }
    }
}

// 迁移后:使用Sealed Classes + Records + Pattern Matching
public sealed interface Shape permits Circle, Rectangle, Triangle {
    double area();
    double perimeter();
}

public record Circle(double radius) implements Shape {
    public Circle {
        if (radius <= 0) {
            throw new IllegalArgumentException("Radius must be positive");
        }
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }

    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }
}

public record Rectangle(double width, double height) implements Shape {
    public Rectangle {
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("Width and height must be positive");
        }
    }

    @Override
    public double area() {
        return width * height;
    }

    @Override
    public double perimeter() {
        return 2 * (width + height);
    }

    public boolean isSquare() {
        return Math.abs(width - height) < 0.001;
    }
}

public record Triangle(double a, double b, double c) implements Shape {
    public Triangle {
        if (a <= 0 || b <= 0 || c <= 0) {
            throw new IllegalArgumentException("All sides must be positive");
        }
        if (a + b <= c || a + c <= b || b + c <= a) {
            throw new IllegalArgumentException("Invalid triangle sides");
        }
    }

    @Override
    public double area() {
        double s = perimeter() / 2;
        return Math.sqrt(s * (s - a) * (s - b) * (s - c));
    }

    @Override
    public double perimeter() {
        return a + b + c;
    }
}

// 现代化的处理方式
public class ModernShapeProcessor {
    public String describeShape(Shape shape) {
        return switch (shape) {
            case Circle(var radius) -> "Circle with radius %.2f".formatted(radius);
            case Rectangle(var width, var height) when Math.abs(width - height) < 0.001 ->
                "Square with side %.2f".formatted(width);
            case Rectangle(var width, var height) ->
                "Rectangle %.2fx%.2f".formatted(width, height);
            case Triangle(var a, var b, var c) ->
                "Triangle with sides %.2f, %.2f, %.2f".formatted(a, b, c);
        };
    }

    public String getShapeCategory(Shape shape) {
        return switch (shape) {
            case Circle c -> "Curved shape";
            case Rectangle r when r.isSquare() -> "Regular polygon";
            case Rectangle r -> "Quadrilateral";
            case Triangle t -> "Polygon";
        };
    }

    public double calculateTotalArea(List<Shape> shapes) {
        return shapes.stream()
            .mapToDouble(Shape::area)
            .sum();
    }
}

实战案例:构建一个类型安全的配置系统

让我们通过一个完整的实战案例来展示Java 17新特性的综合应用:

// 配置系统的核心类型定义
public class ConfigurationSystem {

    // 使用Sealed Interface定义配置值类型
    public sealed interface ConfigValue
        permits StringValue, IntValue, BooleanValue, ListValue, ObjectValue {}

    public record StringValue(String value) implements ConfigValue {
        public StringValue {
            Objects.requireNonNull(value, "String value cannot be null");
        }
    }

    public record IntValue(int value) implements ConfigValue {}

    public record BooleanValue(boolean value) implements ConfigValue {}

    public record ListValue(List<ConfigValue> values) implements ConfigValue {
        public ListValue {
            values = List.copyOf(values); // 防御性复制
        }
    }

    public record ObjectValue(Map<String, ConfigValue> properties) implements ConfigValue {
        public ObjectValue {
            properties = Map.copyOf(properties); // 防御性复制
        }
    }

    // 配置验证结果
    public sealed interface ValidationResult permits Valid, Invalid {}

    public record Valid() implements ValidationResult {}
    public record Invalid(List<String> errors) implements ValidationResult {
        public Invalid {
            errors = List.copyOf(errors);
        }

        public Invalid(String error) {
            this(List.of(error));
        }
    }

    // 配置解析器
    public class ConfigParser {

        public Result<ConfigValue, String> parseValue(String input) {
            input = input.trim();

            // 使用模式匹配进行解析
            return switch (input) {
                case String s when s.equals("true") || s.equals("false") ->
                    Result.success(new BooleanValue(Boolean.parseBoolean(s)));
                case String s when s.matches("-?\\d+") -> {
                    try {
                        yield Result.success(new IntValue(Integer.parseInt(s)));
                    } catch (NumberFormatException e) {
                        yield Result.failure("Invalid integer: " + s);
                    }
                }
                case String s when s.startsWith("\"") && s.endsWith("\"") ->
                    Result.success(new StringValue(s.substring(1, s.length() - 1)));
                case String s when s.startsWith("[") && s.endsWith("]") ->
                    parseList(s);
                case String s when s.startsWith("{") && s.endsWith("}") ->
                    parseObject(s);
                default -> Result.success(new StringValue(input));
            };
        }

        private Result<ConfigValue, String> parseList(String input) {
            // 简化的列表解析逻辑
            String content = input.substring(1, input.length() - 1).trim();
            if (content.isEmpty()) {
                return Result.success(new ListValue(List.of()));
            }

            String[] elements = content.split(",");
            List<ConfigValue> values = new ArrayList<>();

            for (String element : elements) {
                Result<ConfigValue, String> result = parseValue(element.trim());
                if (!result.isSuccess()) {
                    return result;
                }
                values.add(result.value());
            }

            return Result.success(new ListValue(values));
        }

        private Result<ConfigValue, String> parseObject(String input) {
            // 简化的对象解析逻辑
            String content = input.substring(1, input.length() - 1).trim();
            if (content.isEmpty()) {
                return Result.success(new ObjectValue(Map.of()));
            }

            Map<String, ConfigValue> properties = new HashMap<>();
            String[] pairs = content.split(",");

            for (String pair : pairs) {
                String[] keyValue = pair.split(":", 2);
                if (keyValue.length != 2) {
                    return Result.failure("Invalid key-value pair: " + pair);
                }

                String key = keyValue[0].trim();
                if (key.startsWith("\"") && key.endsWith("\"")) {
                    key = key.substring(1, key.length() - 1);
                }

                Result<ConfigValue, String> valueResult = parseValue(keyValue[1].trim());
                if (!valueResult.isSuccess()) {
                    return valueResult;
                }

                properties.put(key, valueResult.value());
            }

            return Result.success(new ObjectValue(properties));
        }
    }

    // 配置验证器
    public class ConfigValidator {

        public ValidationResult validate(ConfigValue value, ConfigSchema schema) {
            return switch (value) {
                case StringValue(var str) -> validateString(str, schema);
                case IntValue(var num) -> validateInt(num, schema);
                case BooleanValue(var bool) -> validateBoolean(bool, schema);
                case ListValue(var list) -> validateList(list, schema);
                case ObjectValue(var obj) -> validateObject(obj, schema);
            };
        }

        private ValidationResult validateString(String value, ConfigSchema schema) {
            List<String> errors = new ArrayList<>();

            if (schema.minLength() > 0 && value.length() < schema.minLength()) {
                errors.add("String too short: minimum length is " + schema.minLength());
            }

            if (schema.maxLength() > 0 && value.length() > schema.maxLength()) {
                errors.add("String too long: maximum length is " + schema.maxLength());
            }

            if (schema.pattern() != null && !value.matches(schema.pattern())) {
                errors.add("String does not match pattern: " + schema.pattern());
            }

            return errors.isEmpty() ? new Valid() : new Invalid(errors);
        }

        private ValidationResult validateInt(int value, ConfigSchema schema) {
            List<String> errors = new ArrayList<>();

            if (schema.minimum() != null && value < schema.minimum()) {
                errors.add("Value too small: minimum is " + schema.minimum());
            }

            if (schema.maximum() != null && value > schema.maximum()) {
                errors.add("Value too large: maximum is " + schema.maximum());
            }

            return errors.isEmpty() ? new Valid() : new Invalid(errors);
        }

        private ValidationResult validateBoolean(boolean value, ConfigSchema schema) {
            return new Valid(); // 布尔值通常不需要额外验证
        }

        private ValidationResult validateList(List<ConfigValue> values, ConfigSchema schema) {
            List<String> errors = new ArrayList<>();

            if (schema.minItems() > 0 && values.size() < schema.minItems()) {
                errors.add("Too few items: minimum is " + schema.minItems());
            }

            if (schema.maxItems() > 0 && values.size() > schema.maxItems()) {
                errors.add("Too many items: maximum is " + schema.maxItems());
            }

            // 验证每个元素
            if (schema.itemSchema() != null) {
                for (int i = 0; i < values.size(); i++) {
                    ValidationResult itemResult = validate(values.get(i), schema.itemSchema());
                    if (itemResult instanceof Invalid(var itemErrors)) {
                        for (String error : itemErrors) {
                            errors.add("Item " + i + ": " + error);
                        }
                    }
                }
            }

            return errors.isEmpty() ? new Valid() : new Invalid(errors);
        }

        private ValidationResult validateObject(Map<String, ConfigValue> properties, ConfigSchema schema) {
            List<String> errors = new ArrayList<>();

            // 检查必需的属性
            for (String required : schema.requiredProperties()) {
                if (!properties.containsKey(required)) {
                    errors.add("Missing required property: " + required);
                }
            }

            // 验证每个属性
            for (Map.Entry<String, ConfigValue> entry : properties.entrySet()) {
                String propertyName = entry.getKey();
                ConfigValue propertyValue = entry.getValue();

                ConfigSchema propertySchema = schema.propertySchemas().get(propertyName);
                if (propertySchema != null) {
                    ValidationResult propertyResult = validate(propertyValue, propertySchema);
                    if (propertyResult instanceof Invalid(var propertyErrors)) {
                        for (String error : propertyErrors) {
                            errors.add("Property " + propertyName + ": " + error);
                        }
                    }
                }
            }

            return errors.isEmpty() ? new Valid() : new Invalid(errors);
        }
    }

    // 配置模式定义
    public record ConfigSchema(
        String type,
        Integer minLength,
        Integer maxLength,
        String pattern,
        Integer minimum,
        Integer maximum,
        Integer minItems,
        Integer maxItems,
        ConfigSchema itemSchema,
        List<String> requiredProperties,
        Map<String, ConfigSchema> propertySchemas
    ) {
        public ConfigSchema {
            requiredProperties = requiredProperties != null ? List.copyOf(requiredProperties) : List.of();
            propertySchemas = propertySchemas != null ? Map.copyOf(propertySchemas) : Map.of();
        }

        // 便利的构造方法
        public static ConfigSchema stringSchema(int minLength, int maxLength, String pattern) {
            return new ConfigSchema("string", minLength, maxLength, pattern, null, null,
                                   null, null, null, null, null);
        }

        public static ConfigSchema intSchema(int minimum, int maximum) {
            return new ConfigSchema("integer", null, null, null, minimum, maximum,
                                   null, null, null, null, null);
        }

        public static ConfigSchema booleanSchema() {
            return new ConfigSchema("boolean", null, null, null, null, null,
                                   null, null, null, null, null);
        }

        public static ConfigSchema listSchema(ConfigSchema itemSchema, int minItems, int maxItems) {
            return new ConfigSchema("array", null, null, null, null, null,
                                   minItems, maxItems, itemSchema, null, null);
        }

        public static ConfigSchema objectSchema(List<String> required, Map<String, ConfigSchema> properties) {
            return new ConfigSchema("object", null, null, null, null, null,
                                   null, null, null, required, properties);
        }
    }
}

// 使用示例
public class ConfigurationExample {
    public void demonstrateConfigSystem() {
        var parser = new ConfigurationSystem().new ConfigParser();
        var validator = new ConfigurationSystem().new ConfigValidator();

        // 解析配置
        String configText = """
            {
                "host": "localhost",
                "port": 8080,
                "ssl": true,
                "features": ["auth", "logging", "metrics"]
            }
            """;

        Result<ConfigValue, String> parseResult = parser.parseValue(configText);

        if (parseResult.isSuccess()) {
            ConfigValue config = parseResult.value();

            // 定义验证模式
            ConfigSchema schema = ConfigSchema.objectSchema(
                List.of("host", "port"),
                Map.of(
                    "host", ConfigSchema.stringSchema(1, 255, null),
                    "port", ConfigSchema.intSchema(1, 65535),
                    "ssl", ConfigSchema.booleanSchema(),
                    "features", ConfigSchema.listSchema(
                        ConfigSchema.stringSchema(1, 50, null), 0, 10)
                )
            );

            // 验证配置
            ValidationResult validationResult = validator.validate(config, schema);

            switch (validationResult) {
                case Valid() -> System.out.println("Configuration is valid");
                case Invalid(var errors) -> {
                    System.out.println("Configuration errors:");
                    errors.forEach(error -> System.out.println("  - " + error));
                }
            }
        } else {
            System.out.println("Parse error: " + parseResult.error());
        }
    }
}

总结与展望

Java 17通过Records、Sealed Classes和Pattern Matching三大特性,为Java语言带来了革命性的变化:

核心价值

  1. 简洁性:Records大幅减少了样板代码,让开发者专注于业务逻辑
  2. 类型安全:Sealed Classes提供了精确的类型控制,减少了运行时错误
  3. 表达力:Pattern Matching使代码更加直观和易读
  4. 函数式编程支持:这些特性为Java引入了更多函数式编程概念

最佳实践总结

  1. Records适用场景

    • 数据传输对象(DTO)
    • 值对象(Value Objects)
    • 不可变数据容器
    • API响应模型
  2. Sealed Classes适用场景

    • 有限状态集合
    • 代数数据类型
    • 领域模型
    • API设计中的封闭类型层次
  3. Pattern Matching适用场景

    • 复杂的条件逻辑
    • 数据解构
    • 类型安全的分支处理
    • 函数式编程风格的代码

未来展望

Java语言的发展方向明确指向更现代、更简洁、更安全的编程体验。随着Project Amber的持续推进,我们可以期待:

  • 更强大的Pattern Matching:支持更复杂的模式和guard条件
  • Value Classes:提供更高效的值类型支持
  • String Templates:类型安全的字符串插值
  • Primitive Classes:统一原始类型和对象类型

Java 17的这些新特性不仅提升了开发效率,更重要的是为Java生态系统的现代化奠定了基础。对于Java开发者而言,掌握这些特性不仅是技术要求,更是拥抱Java未来发展的必要准备。

参考资料

  1. JEP 395: Records
  2. JEP 409: Sealed Classes
  3. JEP 406: Pattern Matching for switch (Preview)
  4. Java 17 Documentation
  5. Oracle Java 17 Release Notes
  6. Inside Java Podcast: Records and Sealed Classes
  7. Project Amber
  8. Java Language Specification - Records
  9. Java Language Specification - Sealed Classes
  10. Effective Java 3rd Edition - Joshua Bloch

本文深入探讨了Java 17中Records、Sealed Classes和Pattern Matching三大核心特性,通过丰富的代码示例和实战案例,展示了这些特性如何改变Java编程范式。希望本文能帮助Java开发者更好地理解和应用这些现代化特性,提升代码质量和开发效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值