blog/source/_posts/nf-java17.md

141 lines
7.0 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Java 17的新特性
tags:
- JVM
- Java
- Java 17
- 新特性
- switch
- 密封类
categories:
- - JVM
- Java
keywords: 'Java,Java 16,新特性,switch,模式匹配,AArch64,密封类,伪随机数生成器'
date: 2022-02-08 09:06:15
---
Java 17是截止到目前最新的长期支持版LTS其实相对于之前的一个Java发行版本Java 17引入的新特性并不多而与日常应用中所密切相关的特性也是比较少的更多的是使之前版本中处于预览和孵化状态的特性转正。<!-- more -->
本系列的文章有:
- {% post_link nf-java8 %}
- {% post_link nf-java9 %}
- {% post_link nf-java10 %}
- {% post_link nf-java11 %}
- {% post_link nf-java12 %}
- {% post_link nf-java13 %}
- {% post_link nf-java14 %}
- {% post_link nf-java15 %}
- {% post_link nf-java16 %}
- {% post_link nf-java17 %}
## 恢复严格浮点模式
在Java 1.2以后受处理器浮点运算性能的影响也为了追求更好的浮点计算性能Java采用了宽松的浮点模式。在宽松模式下Java程序的浮点计算结果是由处理器决定的而不是采用IEEE标准。例如Intel处理器的浮点计算精度为80bit但IEEE标准的浮点精度为64bit那么此时程序在做浮点运算的时候计算结果就会与IEEE标准之间产生误差。这样推广出去相同的程序在不同的硬件平台上可能计算得到的浮点数结果相互之间都不一样这就对程序计算结果的准确性造成了比较大的影响。
但是如果使用Java之前提供的`strictfp`关键字显式声明需要使用严格浮点模式那么程序就会使用IEEE标准对浮点数据进行处理这样一来在不同的硬件平台上浮点计算的结果也就一致了。在Java 17以前要在程序中使用严格浮点模式必须显式使用`strictfp`关键字进行标记在Java 17以后程序进行浮点计算将默认采用严格模式不必再手动使用`strictfp`开启严格模式了。
## 增强了伪随机数生成器
Java 17针对伪随机数生成器PRNG增加了一个新的`RandomGenerator`接口这个接口为所有的PRNG算法提供了统一的API。新增的`RandomGenerator`接口的实例可以通过新增的`RandomGeneratorFactory`工厂类来构建。
例如以下是一个使用指定算法进行随机数生成的示例。
```java
RandomGeneratorFactory<RandomGenerator> randomAlgorithm = RandomGeneratorFactory.of("L128X256MixRandom");
RandomGenerator generator = randomAlgorithm.create(System.currentTimeMillis());
System.out.println(generator.nextInt(10));
```
通过`RandomGeneratorFactory`提供的`all()`方法可以遍历出目前JDK中内置的所有PRNG算法。由于新的API中也内置了老的随机数生成器算法所以使用新的API也是可以调用老的随机数生成器来生成随机数的。
## 提供了对于macOS/AArch64架构的支持
由于Apple在2020年的WWDC中宣布将会将Mac计算机从x64架构逐步过渡到AArch64架构所以为了JDK的平台兼容性必须引入对AArch64架构的支持。
如果开发者现在使用的是新款采用M1系列芯片的Mac笔记本那么现在可以放心的安装使用Java 17了。
## 密封类
密封类在Java 15中被引入现在在Java 17中已经正式转正。密封类相较于之前的Java版本中没有发生任何变化所以可以直接按照之前Java 15新特性中的描述使用。
## 指定上下文的反序列化过滤器
序列化是Java中的一项重要功能通过把对象转换为可以在JVM间自由传输并自动重新构建的能力让数据的远程处理变得更加便捷和透明。但是Java的序列化功能中漏洞也是非常多的例如对象的反序列化就是一个比较危险的动作因为传入的数据流可以自由的引用对象而我们在使用这些内容的时候又不太容易对其进行验证这样就给了攻击者通过伪造和构建攻击代码传入攻击数据流导致整个应用面临巨大的风险。
所以在Java 17中支持在反序列化时通过设置一个过滤配置来通知JVM在本次反序列化的时候允许或者禁止操作的类当反序列化的时候如果碰到了被禁止的类那么整个反序列化过程就会失败。
例如我们有以下两个可以被序列化的类。
```java
@Data
@RequiredArgsConstructor
class Person implements Serializable {
@NonNull
private String name;
private Job job;
}
@Data
@RequiredArgsConstructor
class Job implements Serializable {
@NonNull
private String name;
}
```
那么以下的反序列化操作就会失败。
```java
byte[] objectBytes = personBaos.toByteArray();
ByteArrayInputStream bytesInputStream = new ByteArrayInputStream(objectBytes);
ObjectInputStream objectInputStream = new ObjectInputStream(bytesInputStream);
// 在这里设置反序列化的过滤器,当前语句的设置为允许 xyz.archgrid.demo.entity.person 类、
// java.base 中的所有类,并拒绝其他任何类
ObjectInputFilter filter = ObjectInputFilter.Config
.createFilter("xyz.archgrid.demo.entity.Person;java.base/*;!*");
objectInputStream.setObjectInputFilter(filter);
Object object = objectInputStream.readObject();
```
因为在示例中,`Person`类中使用了`Job`类的实例,但是`Job`类并没有在过滤器列表中列出,所以就会被拒绝。这段代码会抛出一个异常:`java.io.InvalidClassException: filter status: REJECTED`。
## 预览版功能
### Switch模式匹配
Switch表达式自从Java 12引入一来一直在不断的改进和稳定中。在Java 17中Switch表达式增加了可以用于匹配类型的模式匹配功能也就是说Switch表达式可以使用类似于`instanceOf`的功能,来对被测量的内容进行判断。
例如可以使用以下这种复合的判断方式。
```java
String description = switch (someValue) {
case null -> "没有提供有效的值";
case "test" -> "提供了一个字符串类型的测试值";
case String s -> String.format("提供了一个字符串类型的测试值: [%s]", s);
case Integer i -> String.format("提供了一个整型的测试值: [%d]", i);
case Long l -> String.format("提供了一个长整型的测试值: [%d]", l);
case Double d -> String.format("提供了一个双精度浮点类型的测试值: [%f]", d);
default -> "没有列举对于指定类型的判断。";
}
```
## 移除与废弃的功能
以下在之前的Java发布版中已经标记为废弃的API在Java 17中已经被删除。
- Applet API。
- RMI Activation。
- 实验性的AOT和JIT编译器。
以下功能在Java 17中已经被标记为废弃请尽量不要再使用。
- Security Manager。
## 孵化功能
- Vector对于向量的计算功能在Java 17中已经进入二次孵化的阶段主要增强了对字符的操作以及字节向量与布尔数组之间的相互转换等功能。
- 外部函数和内存API这套新的API将允许开发者与JVM之外的代码和数据进行交互可以在不使用JNI的情况下调用系统本地库。