blog/source/_posts/nf-java17.md

7.0 KiB
Raw Blame History

title tags categories keywords date
Java 17的新特性
JVM
Java
Java 17
新特性
switch
密封类
JVM
Java
Java,Java 16,新特性,switch,模式匹配,AArch64,密封类,伪随机数生成器 2022-02-08 09:06:15

Java 17是截止到目前最新的长期支持版LTS其实相对于之前的一个Java发行版本Java 17引入的新特性并不多而与日常应用中所密切相关的特性也是比较少的更多的是使之前版本中处于预览和孵化状态的特性转正。

本系列的文章有:

  • {% 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工厂类来构建。

例如以下是一个使用指定算法进行随机数生成的示例。

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在本次反序列化的时候允许或者禁止操作的类当反序列化的时候如果碰到了被禁止的类那么整个反序列化过程就会失败。

例如我们有以下两个可以被序列化的类。

@Data
@RequiredArgsConstructor
class Person implements Serializable {
  @NonNull
  private String name;
  private Job job;
}

@Data
@RequiredArgsConstructor
class Job implements Serializable {
  @NonNull
  private String name;
}

那么以下的反序列化操作就会失败。

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的功能,来对被测量的内容进行判断。

例如可以使用以下这种复合的判断方式。

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的情况下调用系统本地库。