荒原曙光
3.49GB · 2025-11-20
Java 15 作为2020年9月发布的版本,引入了14个重要的增强特性(JEPs),其中包含了多个备受关注的预览特性和正式特性。相比Java 14,此版本在开发效率、代码简洁性和性能方面都有显著提升。
从Java 15开始预览,JEP 360引入了密封类的概念,这是对Java继承机制的重要补充。
传统的Java类要么完全开放继承(public class),要么完全禁止继承(final class),缺少中间状态。密封类提供了精确控制哪些类可以继承的能力。
通过sealed关键字和permits子句,限制只有指定的类才能继承该密封类,提供了比访问修饰符更细粒度的控制。
// 新写法 - 使用密封类
public sealed class Shape
permits Circle, Rectangle, Triangle {
protected final String name;
protected Shape(String name) {
this.name = name;
}
public abstract double area();
}
// 只有这三个类可以继承Shape
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
super("Circle");
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) {
super("Rectangle");
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) {
super("Triangle");
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
}
// 使用示例
public class ShapeProcessor {
public static void processShape(Shape shape) {
// 编译器知道所有可能的子类型
switch (shape) {
case Circle c -> System.out.println("处理圆形,面积:" + c.area());
case Rectangle r -> System.out.println("处理矩形,面积:" + r.area());
case Triangle t -> System.out.println("处理三角形,面积:" + t.area());
}
}
}
从Java 13开始预览,经过两个版本的完善,在Java 15中正式成为标准特性。
传统的多行字符串处理需要大量的转义字符和字符串拼接,代码可读性差,维护困难。
public class TextBlockExample {
// 旧写法 - 传统字符串拼接
public static String oldJsonExample() {
return "{n" +
" "name": "张三",n" +
" "age": 30,n" +
" "address": {n" +
" "city": "北京",n" +
" "zipCode": "100000"n" +
" }n" +
"}";
}
// 新写法 - 使用文本块
public static String newJsonExample() {
return """
{
"name": "张三",
"age": 30,
"address": {
"city": "北京",
"zipCode": "100000"
}
}
""";
}
// HTML模板示例
public static String htmlTemplate(String title, String content) {
return """
<!DOCTYPE html>
<html>
<head>
<title>%s</title>
</head>
<body>
<h1>%s</h1>
<p>%s</p>
</body>
</html>
""".formatted(title, title, content);
}
// SQL查询示例
public static String complexQuery() {
return """
SELECT u.id, u.name, u.email,
p.title, p.content, p.created_date
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
WHERE u.status = 'ACTIVE'
AND p.published = true
ORDER BY p.created_date DESC
LIMIT 10
""";
}
public static void main(String[] args) {
System.out.println("=== JSON示例 ===");
System.out.println(newJsonExample());
System.out.println("n=== HTML示例 ===");
System.out.println(htmlTemplate("我的博客", "欢迎来到我的博客"));
System.out.println("n=== SQL示例 ===");
System.out.println(complexQuery());
}
}
n和"第二次预览特性,继续完善这个用于创建不可变数据载体的语法糖。
// 新写法 - 使用Record
public record Person(String name, int age, String email) {
// 自定义构造器验证
public Person {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("邮箱格式不正确");
}
}
// 添加自定义方法
public boolean isAdult() {
return age >= 18;
}
// 格式化显示
public String getDisplayName() {
return name + " (" + age + "岁)";
}
}
// 传统写法对比 - 等效的普通类
public final class PersonTraditional {
private final String name;
private final int age;
private final String email;
public PersonTraditional(String name, int age, String email) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("邮箱格式不正确");
}
this.name = name;
this.age = age;
this.email = 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;
PersonTraditional that = (PersonTraditional) obj;
return age == that.age &&
Objects.equals(name, that.name) &&
Objects.equals(email, that.email);
}
@Override
public int hashCode() {
return Objects.hash(name, age, email);
}
@Override
public String toString() {
return "PersonTraditional{name='" + name + "', age=" + age +
", email='" + email + "'}";
}
}
// 使用示例
public class RecordExample {
public static void main(String[] args) {
// 创建Record实例
Person person = new Person("张三", 25, "[email protected]");
// 自动生成的访问器方法
System.out.println("姓名:" + person.name());
System.out.println("年龄:" + person.age());
System.out.println("邮箱:" + person.email());
// 自动生成的toString()
System.out.println("完整信息:" + person);
// 自定义方法
System.out.println("是否成年:" + person.isAdult());
System.out.println("显示名称:" + person.getDisplayName());
// 创建另一个实例测试equals
Person person2 = new Person("张三", 25, "[email protected]");
System.out.println("两个对象相等:" + person.equals(person2));
}
}
第二次预览特性,简化类型检查和转换的常见模式。
public class PatternMatchingExample {
// 旧写法 - 传统instanceof
public static String oldProcessObject(Object obj) {
String result = "未知类型";
if (obj instanceof String) {
String str = (String) obj; // 需要显式转换
result = "字符串长度:" + str.length();
} else if (obj instanceof Integer) {
Integer num = (Integer) obj; // 需要显式转换
result = "整数值:" + num;
} else if (obj instanceof Double) {
Double d = (Double) obj; // 需要显式转换
result = "小数值:" + String.format("%.2f", d);
}
return result;
}
// 新写法 - 使用模式匹配
public static String newProcessObject(Object obj) {
return switch (obj) {
case String str -> "字符串长度:" + str.length();
case Integer num -> "整数值:" + num;
case Double d -> "小数值:" + String.format("%.2f", d);
case null -> "空值";
default -> "未知类型";
};
}
// 复杂的模式匹配示例
public static void processShape(Object shape) {
if (shape instanceof Circle c && c.radius() > 10) {
System.out.println("大圆形,半径:" + c.radius());
} else if (shape instanceof Rectangle r && r.width() * r.height() > 100) {
System.out.println("大矩形,面积:" + (r.width() * r.height()));
} else if (shape instanceof String s && s.startsWith("shape:")) {
System.out.println("形状描述:" + s.substring(6));
}
}
// 实际应用场景 - JSON处理
public static void processJsonValue(Object value) {
switch (value) {
case String str when str.startsWith("http") ->
System.out.println("这是一个URL:" + str);
case String str ->
System.out.println("文本内容:" + str);
case Integer num when num > 0 ->
System.out.println("正整数:" + num);
case Integer num ->
System.out.println("非正整数:" + num);
case Boolean bool ->
System.out.println("布尔值:" + bool);
case null ->
System.out.println("空值");
default ->
System.out.println("其他类型:" + value.getClass().getSimpleName());
}
}
public static void main(String[] args) {
Object[] testData = {
"Hello World",
42,
3.14159,
null,
new java.util.Date()
};
System.out.println("=== 传统方式 ===");
for (Object obj : testData) {
System.out.println(oldProcessObject(obj));
}
System.out.println("n=== 模式匹配方式 ===");
for (Object obj : testData) {
System.out.println(newProcessObject(obj));
}
}
}
// 辅助类
record Circle(double radius) {}
record Rectangle(double width, double height) {}
ZGC(JEP 377)和Shenandoah GC(JEP 379)从实验性特性升级为生产就绪特性。
传统GC在大堆内存场景下会产生明显的停顿时间,影响应用响应性能。
文本块的正式发布解决了多行字符串的历史痛点,密封类和记录类的预览为Java带来了更现代化的类型系统