Java 17 的新特性
JDK 17 带来了多项新特性和改进,这些特性旨在提升Java语言的性能、易用性和安全性。以下是JDK 17的一些主要新特性:
1. Switch表达式增强
模式匹配:JDK 17中的switch表达式引入了模式匹配,包括类型模式和守卫模式。这允许在switch表达式中直接使用instanceof进行类型检查和转换,无需显式转换。
语法简化:switch表达式中的case语句可以使用箭头(->)来直接返回结果,而无需使用break语句。同时,支持使用逗号分隔多个case标签,以便它们共享相同的代码块。
对null值的支持:Switch表达式还允许我们直接处理
null
值,而无需在之前进行显式的null
检查。例子
public void handleObject(Object obj) {
String result = switch (obj) {
case String s -> "处理字符串: " + s;
case Integer i -> "处理整数: " + i;
case List<?> list -> "处理列表";
case null -> "处理null值";
default -> "未知类型";
};
System.out.println(result);
}
// 使用示例
public static void main(String[] args) {
HandleObjectDemo demo = new HandleObjectDemo();
demo.handleObject("Hello, JDK 17!");
demo.handleObject(123);
demo.handleObject(List.of("a", "b", "c"));
demo.handleObject(null);
demo.handleObject(new Object());
}
2. 文本块(Text Blocks)
多行字符串:文本块允许开发者以更自然、更易于阅读的方式编写多行字符串。它使用三个双引号(""")来定义字符串的开始和结束,并且支持在字符串内部包含换行符和缩进。
转义字符:JDK 17对文本块进行了增强,提供了两个转义符(\ 和 \s\)用于将两行强制连接为一行或添加空白字符。
例子
String html = """
<html>
<body>
<h1>Hello, World!</h1>
<p>This is a text block example.</p>
</body>
</html>
""";
System.out.println(html);
3. 伪随机数生成器(PRNG)
增强型伪随机数生成器:JDK 17增加了伪随机数相关的类和接口,允许开发者使用stream流来操作随机数生成。这些新特性提供了更灵活、更强大的随机数生成能力。
例子
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
public class RandomNumberDemo {
public static void main(String[] args) {
// 使用RandomGeneratorFactory获取一个RandomGenerator实例
// 这里以"L64X1024MixRandom"为例,它是一个具体的PRNG算法名称
RandomGeneratorFactory<RandomGenerator> factory = RandomGeneratorFactory.of("L64X1024MixRandom");
RandomGenerator rng = factory.create(System.currentTimeMillis()); // 使用当前时间作为种子
// 生成并打印一个随机整数
int randomNumber = rng.nextInt();
System.out.println("Random number: " + randomNumber);
// 生成并打印一系列指定范围内的随机整数
for (int i = 0; i < 10; i++) {
int randomInRange = rng.nextInt(10); // 生成0到9之间的随机整数
System.out.println(randomInRange);
}
}
}
// PRNG算法
LXM:L32X64MixRandom
LXM:L128X128MixRandom
LXM:L64X128MixRandom
Legacy:SecureRandom
LXM:L128X1024MixRandom
LXM:L64X128StarStarRandom
Xoshiro:Xoshiro256PlusPlus
LXM:L64X256MixRandom
Legacy:Random
Xoroshiro:Xoroshiro128PlusPlus
LXM:L128X256MixRandom
Legacy:SplittableRandom
LXM:L64X1024MixRandom
4. 上下文特定的反序列化过滤器
Java序列化是核心功能,其重要性不言而喻,是Java在开发领域占据主导的关键之一。它简化了远程通信,并推动了Java EE的蓬勃发展。然而,Java序列化机制亦饱受诟病,其设计上的不足常导致诸多错误与维护难题。本质上,序列化概念无误,即将对象转换为跨JVM传输并可重建的格式,问题出在Java的实现上,频繁曝出安全漏洞。
反序列化风险高,因难以确保数据安全性,恶意数据流可能包含攻击代码,自由引用对象加剧了这一风险。
为此,JEP 415引入反序列化过滤机制,通过配置允许或禁止特定类的操作,有效遏制了潜在的安全威胁,确保被禁止的类在反序列化时失败,增强了系统的安全性。
例子:
首先,我们需要定义一个可序列化的类:
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
// 构造函数、getter和setter省略
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
然后,我们编写一个主类来演示如何使用
ObjectInputFilter
来限制反序列化过程中可接受的类:
import java.io.*;
public class SerializationDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 序列化示例
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
User user = new User("Alice", 30);
objectOutputStream.writeObject(user);
objectOutputStream.close();
// 假设这是从网络或其他来源接收到的字节流
byte[] data = byteArrayOutputStream.toByteArray();
// 使用ObjectInputFilter来限制反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data)) {
{
// 只允许User类被反序列化
this.setObjectInputFilter(obj -> {
if (obj instanceof Class && "User".equals(((Class<?>) obj).getSimpleName())) {
return true;
}
return false;
});
}
};
try {
// 尝试反序列化
Object deserializedObject = objectInputStream.readObject();
System.out.println(deserializedObject);
} catch (InvalidClassException e) {
System.err.println("反序列化被拒绝,因为类不符合过滤器规则。");
}
objectInputStream.close();
}
}
注意:上面的ObjectInputStream
匿名子类示例是概念性的,用于说明如何可能实现一个过滤器。然而,在Java标准库中,ObjectInputStream
并没有直接提供这样的构造函数或方法来设置过滤器。实际上,你需要使用ObjectInputFilter.Config
来配置过滤器,但这通常是通过ObjectInputStream.setObjectInputFilter
方法设置的,而该方法接受的是一个ObjectInputFilter
实例,而不是在构造函数中设置。
由于Java API的限制,上面的代码示例需要稍作调整以符合实际使用方式。下面是一个更准确的示例,展示如何设置ObjectInputFilter
:
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data));
// 定义一个简单的过滤器
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"allowed.classes",
User.class.getName() // 只允许User类
);
objectInputStream.setObjectInputFilter(filter);
Object object = objectInputStream.readObject();
System.out.println(object.toString());
5. 密封类(Sealed Classes)
控制继承:密封类允许类或接口的作者控制哪些类可以继承或实现它们。这通过关键字sealed、non-sealed和permits来实现,提供了比访问修饰符更具声明性的方式来限制超类的使用。
安全性:密封类有助于创建更加安全和可维护的代码库,因为它限制了未经授权的类继承,减少了意外扩展的可能性。
6. 弃用和移除
Applet API:JDK 17弃用了Applet API,并计划在后续版本中移除。这反映了Applet技术在现代Web应用中的过时和不安全。
安全管理器(Security Manager):JDK 17也弃用了安全管理器,并计划在后续版本中移除。安全管理器可追溯到Java 1.0,但多年来一直不是保护Java代码的主要手段。
7. 其他新特性
恢复始终严格模式的浮点语义:修复了25年前英特尔浮点指令的一些问题,恢复了始终执行严格模式的浮点定义。
新增macOS渲染管道:提供了对macOS平台的新渲染支持。
支持将JDK移植到macOS或AArch64:增强了JDK的跨平台能力。
强封装JDK内部API:提高了JDK内部API的封装性,减少了外部对内部实现的依赖。
移除RMI(远程方法调用)激活机制:简化了RMI的使用和配置。
外部函数和内存API(孵化器):允许Java程序与Java运行时之外的代码和数据进行互操作。
Vector API(第二孵化器):引入了一个API来表达向量计算,以实现优于等效标量计算的性能。
总的来说,JDK 17带来了多项重要的新特性和改进,这些特性旨在提升Java语言的性能、易用性和安全性。随着Spring Boot 3.0等框架对JDK 17的支持,越来越多的开发者将开始使用JDK 17来构建新的应用程序。
评论区