jdk17 新特性

Posted by eliooyang on 2023-05-26
Words 2.1k and Reading Time 8 Minutes
Viewed Times
关注版本更新,享受技术红利

参考文档:

jdk17新特性,oracle文档

jdk17官方文档

jdk17商用协议

是否说在jdk更新的版本中,不知道有什么新特性可以提高我们的开发效率,或者说新特性可以完成什么新需求?

为了更好利用到版本更新的红利,本文为简单化了解一下,jdk17相对于8有什么新特性。

1.JDK17相关特性

stream 优化

总所周知,在jdk1.8中引入Stream-Api的流。

1.switch 增强

switch的模式匹配优化。 switch是仅支持同一种数据类型的判断。
在多个jdk版本的优化后在jdk17迎来最终的优化,原本需要进行null的判断,且switch不支持类型的判断。

JDK17语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SwitchDemo{
public static void main(String[] args) {
Object o;
switch (o) {
case null -> System.out.println("判断是否为null");
case String s -> System.out.println("判断是否为字符串,s:" + s);
case record p -> System.out.println("判断是否为Record类型: " + p.toString());
case int[] arr -> System.out.println("判断是否为数组,长度" + ia.length);
case Integer i -> System.out.println("判断是否为Intger,i:" + i);
case Student s -> System.out.println("判断是否为自定义对象,student:" + s.toString());
default -> System.out.println("Something else");
}
}
}

switch的增强历程,instanceof的模式匹配:

  • JDK14作为preview,
  • 在JDK15作为第二轮的preview,
  • 在JDK16转正

2.恢复始终严格的浮点语义

3.增强型伪随机数发生器

伪随机数生成器(PRNG)提供新的接口类型和实现,使程序使用各种PRNG算法更加容易,更好的支持流式编程。

PRNG伪随机数,随机数会作用于下一个随机数,高效,周期性,确定性等特点,经常用于数学建模等场景。

提供RandomGenerator统一生成PRNG的api,并提供工厂RandomGeneratorFactory生成实例

1
2
3
4
5
6
7
8
9
10
class PRNGDemo {
public static void main(String[] args) {
//生成10个10以内的随机数
RandomGeneratorFactory<RandomGenerator> L128X1024MixRandom = RandomGeneratorFactory.of("L128X1024MixRandom");
RandomGenerator randomGenerator = L128X1024MixRandom.create(System.currentTimeMillis());
for (int i = 0; i < 10; i++) {
System.out.println(randomGenerator.nextInt(10));
}
}
}

4. macOs渲染管道

MACOS支持渲染内容

主要是支持macos的一些ui渲染的支持。为了兼容Apple的渲染管道macOSMetal,Apple准备弃用的OpenGL API作的更新。
同时也兼容OpenGL的使用,知道被启用为止。

5. 支持macOS/AArch64平台支持,虚拟机跨平台的支持

兼容系统的协议
可将jdk移植到macOS/AArch64,上述系统有(W^X)的策略,禁止内存段同时可执行可写。
HotSpot VM定期创建和修改可执行代码,因此JEP将在HotSpot for macOS/AArch64中实现W^X支持。

人家有用户就是霸气,乙方就得兼容。

6。删除已弃用Applet API

APPLET弃用
稍微介绍一下Applet是什么,为何弃用。

功能: 一般运行在支持Java的Web浏览器,Java客户端的运行浏览器,有自己的生命周期。
例如这种,年轻人们是不是没见过,取消这个Applet的生态主要是现在前端生态百花齐放,基本没有运用场景了。

img.png

7.移除RMI

Remove RMI Activation

满足好奇心,什么是rmi,下面是demo:

rmi 是一种远程通信协议,通过接口进行通信。

server端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class RmiServer {
public static void main(String []args) {
try {
//创建一个远程对象
IRmi rmiHello = new RmiImpl();

//远程主机远程对象注册表Registry的实例,并指定端口为8888,这一步必不可少(Java默认端口是1099),
// 必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上
LocateRegistry.createRegistry(8888);

//把远程对象注册到RMI注册服务器上,并命名为RHello
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://localhost:8888/RmiHello",rmiHello);
//Naming.bind("//localhost:8888/RmiHello",rmiHello);

//必须捕获这三个异常,否则需要在main方法中抛出
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("URL畸形异常");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("重复绑定对象异常");
e.printStackTrace();
}
}

}

client端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HelloClient {
public static void main(String []args) {
try {
//在RMI服务注册表中查找名称为RHello的对象,并调用其上的方法
IRmi localHello = (IHello)Naming.lookup("rmi://localhost:8888/RmiHello");
System.out.println(localHello.say());
System.out.println(localHello.sayTo("11111"));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}

8.密封类

Sealed Classes

主要是做接口限制,指定哪些类可以实现或者扩展。

sealed声明密封类, permits声明可以继承的类;
仅有 Circle,Rectangle,Square可以继承Shape

1
2
3
4
public abstract sealed class Shape 
permits Circle,
Rectangle,
Square { }

// todo

9.移除AOT及JIT Compiler

Remove the Experimental AOT and JIT Compiler

原本的Java编译流程是JIT编译

AOT 提前编译,优化spring框架启动慢,占用内存多的特性,垃圾无法被回收问题。

spring Native基于Graal VM编译成原生镜像,云原生友好

10.废弃Security Manager

Deprecate the Security Manager for Removal

这个是从java1.0保护客户端的代码,服务于Applet。也是由于发展原因随着Applet一起被删除。

11.外部函数和内存API

Foreign Function & Memory API (Incubator)

新的API,Java程序可以与Java运行时之外的代码和数据进行互操作。通过有效地调用外部函数(即JVM外部的代码),并安全地访问外部内存(即不由JVM管理的内存),API使Java程序能够调用本地库并处理本地数据,而不会出现JNI的脆弱性和危险。

以前是通过JNI去调用C++/C代码取跟内存进行交互的,这里是指JVM内存结构内以外的内存,现在提供一套API替换JNI的功能

  • 易用性,相对于JNI更容易使用,java开发的模型对象
  • 性能与现有的JNI与sun.misc.Unsafe相比不差
  • 安全性上,默认禁用不安全操作

分配外部内存:MemorySegment,MemoryAddress,SegmentAllocator

操作和访问结构化外部内存:MemoryLayout,MemoryHandles,MemoryAccess

管理外部资源的生命周期:ResourceScope

调用外部函数 SymbolLookup,CLinker

举例子
MemorySegment 连续内存的模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MemoryDemo{
public static void main(String[] args) {
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
int sum = StreamSupport.stream(MemorySegment.spliterator(segment.withOwnerThread(null),seq_bulk),true)
.mapToInt(slice -> {
int res = 0;
for (int i = 0; i < 100 ; i++) {
res += MemoryAccess.getIntAtIndex(slice, i);
}
return res;
}).sum();
}
}
}

12.矢量API

Vector API (Second Incubator)

向量API是从JDK16开始引入的。
向量相关定义API,三维向量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class VectorDemo {
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
void vectorComputation(float[] a, float[] b, float[] c) {

for (int i = 0; i < a.length; i += SPECIES.length()) {
var m = SPECIES.indexInRange(i, a.length);
// FloatVector va, vb, vc;
var va = FloatVector.fromArray(SPECIES, a, i, m);
var vb = FloatVector.fromArray(SPECIES, b, i, m);
var vc = va.mul(va).
add(vb.mul(vb)).
neg();
vc.intoArray(c, i, m);
}
}
}

个人感觉应用不多,忽略忽略

13.实现特定于上下文的反序列化过滤器

Context-Specific Deserialization Filters

对不受信任的数据进行反序列化是一种固有的危险活动,因为传入数据流的内容决定了创建的对象、其字段的值以及它们之间的引用。

在许多典型的使用中,流中的字节是从未知、不可信或未经身份验证的客户端接收的。

通过小心地构造流,对手可能会导致恶意执行任意类中的代码。

如果对象构造有改变状态或调用其他操作的副作用,这些操作可能会危及应用程序对象、库对象甚至Java运行时的完整性。

关键是防止任意类的实例被反序列化,从而防止直接或间接地执行它们的方法。

简而言之,就是在数据流在反序列化之前可以通过自定义过滤器去做校验,验证这个数据的安全性。
原本JDK9引入了数据流的反序列化功能,就是嫌弃流操作太麻烦了,jdk17又提供了API形式的反序列化类。
BinaryOperator<ObjectInputFilter>


你的支持是我加班的动力
微信
支付宝

This is copyright.

...

...

00:00
00:00