第69章

Java 17新特性

深入学习Java 17 LTS版本的重要新特性:密封类、记录类、模式匹配、文本块等现代Java编程特性

学习目标

Java 17概述

Java 17 LTS版本

Java 17是继Java 11之后的第二个长期支持(LTS)版本,于2021年9月发布。作为LTS版本,Java 17将获得长期的支持和维护,是企业级应用的理想选择。

Java 17引入了许多重要的新特性,这些特性不仅提高了开发效率,还增强了代码的可读性和安全性。主要新特性包括:

密封类

  • 限制类的继承层次结构
  • 提供更好的API设计控制
  • 增强模式匹配支持
  • 编译时类型安全保证

记录类

  • 简洁的不可变数据载体
  • 自动生成构造器和访问器
  • 内置equals、hashCode和toString
  • 减少样板代码

模式匹配

  • instanceof的模式匹配
  • switch表达式增强
  • 减少类型转换代码
  • 提高代码可读性

文本块

  • 多行字符串字面量
  • 保持原始格式
  • 减少转义字符
  • 提高代码可读性

密封类(Sealed Classes)

密封类是Java 17中引入的一个重要特性,它允许开发者限制哪些类可以继承或实现某个类或接口。这提供了比传统的final关键字更灵活的继承控制。

基本语法

密封类示例
public sealed class Shape permits Circle, Rectangle, Triangle {
    protected final String name;
    
    protected Shape(String name) {
        this.name = name;
    }
    
    public abstract double getArea();
    
    public String getName() {
        return name;
    }
}

final class Circle extends Shape {
    private final double radius;
    
    public Circle(double radius) {
        super("圆形");
        this.radius = radius;
    }
    
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
    
    public double getRadius() {
        return radius;
    }
}

final class Rectangle extends Shape {
    private final double width;
    private final double height;
    
    public Rectangle(double width, double height) {
        super("矩形");
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double getArea() {
        return width * height;
    }
}

non-sealed class Triangle extends Shape {
    private final double base;
    private final double height;
    
    public Triangle(double base, double height) {
        super("三角形");
        this.base = base;
        this.height = height;
    }
    
    @Override
    public double getArea() {
        return 0.5 * base * height;
    }
}

密封类的优势

  • 类型安全:编译时确保只有指定的类可以继承
  • 模式匹配:与switch表达式完美配合
  • API设计:更好地控制类的继承层次
  • 文档化:明确表达设计意图

记录类(Record Classes)

记录类是Java 14引入并在Java 17中稳定的特性,它提供了一种简洁的方式来创建不可变的数据载体类。记录类自动生成构造器、访问器方法以及equals、hashCode和toString方法。

基本用法

记录类示例
public record Person(String name, int age, String email) {
    // 紧凑构造器 - 用于验证和规范化
    public Person {
        Objects.requireNonNull(name, "姓名不能为空");
        Objects.requireNonNull(email, "邮箱不能为空");
        
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("年龄必须在0-150之间");
        }
        
        if (!email.contains("@")) {
            throw new IllegalArgumentException("邮箱格式不正确");
        }
    }
    
    // 自定义方法
    public boolean isAdult() {
        return age >= 18;
    }
    
    public String getDisplayName() {
        return isAdult() ? name + " (成年)" : name + " (未成年)";
    }
    
    // 静态工厂方法
    public static Person of(String name, int age, String email) {
        return new Person(name, age, email);
    }
}

// 嵌套记录类
record Address(String street, String city, String zipCode, String country) {
    public String getFullAddress() {
        return String.format("%s, %s %s, %s", street, city, zipCode, country);
    }
}

// 使用示例
class RecordDemo {
    public static void main(String[] args) {
        Person person = new Person("张三", 28, "zhangsan@example.com");
        
        System.out.println("姓名: " + person.name());
        System.out.println("年龄: " + person.age());
        System.out.println("邮箱: " + person.email());
        System.out.println("是否成年: " + person.isAdult());
        System.out.println("显示名称: " + person.getDisplayName());
        
        Address address = new Address("中关村大街1号", "北京", "100080", "中国");
        System.out.println("完整地址: " + address.getFullAddress());
    }
}

模式匹配

模式匹配是Java中一个强大的特性,它简化了类型检查和转换的代码。Java 17中的模式匹配主要体现在instanceof操作符和switch表达式中。

instanceof模式匹配

instanceof模式匹配示例
public class PatternMatchingExample {
    public static void processObject(Object obj) {
        // 传统方式
        if (obj instanceof String) {
            String str = (String) obj;
            System.out.println("字符串长度: " + str.length());
        }
        
        // Java 17模式匹配方式
        if (obj instanceof String str) {
            System.out.println("字符串长度: " + str.length());
        } else if (obj instanceof Integer num) {
            System.out.println("整数平方: " + (num * num));
        } else if (obj instanceof List list) {
            System.out.println("列表大小: " + list.size());
        }
    }
}

switch模式匹配

switch模式匹配示例
public class SwitchPatternMatching {
    public static String analyzeObject(Object obj) {
        return switch (obj) {
            case null -> "对象为null";
            case String s -> "字符串: \"" + s + "\", 长度: " + s.length();
            case Integer i when i > 0 -> "正整数: " + i;
            case Integer i when i < 0 -> "负整数: " + i;
            case Integer i -> "零: " + i;
            case List list when list.isEmpty() -> "空列表";
            case List list -> "非空列表,大小: " + list.size();
            default -> "其他类型: " + obj.getClass().getSimpleName();
        };
    }
    
    // 与密封类结合使用
    public static String describeShape(Shape shape) {
        return switch (shape) {
            case Circle c -> String.format("圆形: 半径=%.2f, 面积=%.2f", 
                c.getRadius(), c.getArea());
            case Rectangle r -> String.format("矩形: 宽度=%.2f, 高度=%.2f, 面积=%.2f", 
                r.getWidth(), r.getHeight(), r.getArea());
            case Triangle t -> String.format("三角形: 底边=%.2f, 高度=%.2f, 面积=%.2f", 
                t.getBase(), t.getHeight(), t.getArea());
        };
    }
}

文本块(Text Blocks)

文本块是Java 15引入的特性,它允许开发者创建多行字符串字面量,而无需使用大量的转义字符和字符串连接操作。

文本块示例
public class TextBlockExample {
    public static void demonstrateTextBlocks() {
        // 传统方式创建HTML
        String traditionalHtml = "\n" +
                                "  \n" +
                                "    页面标题\n" +
                                "  
\n" +
                                "  \n" +
                                "    

欢迎使用Java 17

\n" + " \n" + ""; // 使用文本块创建HTML String textBlockHtml = \"\"\" 页面标题

欢迎使用Java 17

\"\"\"; // JSON示例 String jsonData = \"\"\" { "name": "张三", "age": 28, "address": { "street": "中关村大街1号", "city": "北京", "zipCode": "100080" }, "hobbies": ["编程", "阅读", "旅行"] } \"\"\"; System.out.println("HTML内容:"); System.out.println(textBlockHtml); System.out.println("\nJSON数据:"); System.out.println(jsonData); } }

文本块的优势

  • 可读性:保持原始格式,提高代码可读性
  • 维护性:减少转义字符,降低维护成本
  • 灵活性:支持字符串格式化和插值
  • 适用性:特别适合HTML、JSON、SQL等多行文本

完整代码示例

下面是一个综合展示Java 17新特性的完整示例:

Java 17新特性综合示例
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Random;

public class Java17FeaturesDemo {
    public static void main(String[] args) {
        System.out.println("🚀 欢迎使用Java 17新特性演示程序!");
        
        // 使用文本块创建JSON模板
        String jsonTemplate = \"\"\"
                {
                  "timestamp": "%s",
                  "features": [
                    {
                      "name": "Sealed Classes",
                      "description": "限制类的继承层次结构"
                    },
                    {
                      "name": "Record Classes",
                      "description": "简洁的不可变数据载体"
                    }
                  ]
                }
                \"\"\";
        
        String currentTime = LocalDateTime.now()
            .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        String json = jsonTemplate.formatted(currentTime);
        System.out.println("生成的JSON:");
        System.out.println(json);
        
        // 使用记录类
        List features = List.of(
            new FeatureInfo("Sealed Classes", "JEP 409", 17, true),
            new FeatureInfo("Record Classes", "JEP 395", 14, true),
            new FeatureInfo("Text Blocks", "JEP 378", 15, true)
        );
        
        System.out.println("\n=== Java新特性列表 ===");
        features.forEach(feature -> {
            System.out.println(feature.getDescription());
        });
        
        // 使用模式匹配
        Object[] testData = {
            "Java 17 LTS",
            features.size(),
            features,
            new Random().nextDouble()
        };
        
        System.out.println("\n=== 模式匹配处理 ===");
        for (Object data : testData) {
            String result = analyzeData(data);
            System.out.println(result);
        }
    }
    
    private static String analyzeData(Object data) {
        return switch (data) {
            case String s when s.contains("Java") -> "Java相关字符串: " + s;
            case String s -> "普通字符串: " + s;
            case Integer i when i > 10 -> "大整数: " + i;
            case Integer i -> "小整数: " + i;
            case List list when !list.isEmpty() -> 
                "非空列表,包含 " + list.size() + " 个元素";
            case List list -> "空列表";
            case Double d -> "浮点数: " + String.format("%.2f", d);
            default -> "未知类型: " + data.getClass().getSimpleName();
        };
    }
}

// 记录类定义
record FeatureInfo(String name, String jep, int introducedVersion, boolean isStable) {
    public String getDescription() {
        String status = isStable ? "稳定" : "预览";
        return String.format("📋 %s (%s) - Java %d引入 [%s]", 
            name, jep, introducedVersion, status);
    }
}
💻 查看完整代码 - 在线IDE体验

Java 17新特性最佳实践

使用建议

  • 密封类:用于限制继承层次,特别适合状态机和数据模型
  • 记录类:优先用于不可变数据传输对象(DTO)
  • 模式匹配:简化类型检查和转换,提高代码可读性
  • 文本块:用于多行字符串,特别是HTML、JSON、SQL等
  • 性能考虑:新特性在提高开发效率的同时保持良好性能

本章小结