Java 15 新特性概述
Java 15 新特性概述
JDK 15 在 2020 年 9 月 15 号正式发布了!根据发布的规划,这次发布的 JDK 15 将是一个短期的过度版,只会被 Oracle 支持(维护)6 个月,直到明年 3 月的 JDK 16 发布此版本将停止维护。而 Oracle 下一个长期支持版(LTS 版)会在明年的 9 月份候发布(Java 17),LTS 版每 3 年发布一个,上一次长期支持版是 18 年 9 月发布的 JDK 11。@pdai
知识体系

[JEP355: 文本块(预览功能)
语言特性增强
JEP 378: 文本块(Text Blocks)
文本块,是一个多行字符串,它可以避免使用大多数转义符号,自动以可预测的方式格式化字符串,并让开发人员在需要时可以控制格式。
Text Blocks首次是在JDK 13中以预览功能出现的,然后在JDK 14中又预览了一次,终于在JDK 15中被确定下来,可放心使用了。
public static void main(String[] args) {
String query = """
SELECT * from USER \
WHERE `id` = 1 \
ORDER BY `id`, `name`;\
""";
System.out.println(query);
}
运行程序,输出(可以看到展示为一行了):
SELECT * from USER WHERE `id` = 1 ORDER BY `id`, `name`;
新功能和库的更新
JEP 339: Edwards-Curve 数字签名算法 (EdDSA)
Edwards-Curve 数字签名算法(EdDSA),一种根据 RFC 8032 规范所描述的 Edwards-Curve 数字签名算法(EdDSA)实现加密签名,实现了一种 RFC 8032 标准化方案,但它不能代替 ECDSA。
与 JDK 中的现有签名方案相比,EdDSA 具有更高的安全性和性能,因此备受关注。它已经在OpenSSL和BoringSSL等加密库中得到支持,在区块链领域用的比较多。
EdDSA是一种现代的椭圆曲线方案,具有JDK中现有签名方案的优点。EdDSA将只在SunEC提供商中实现。
// example: generate a key pair and sign
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();
// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
JEP 371: 隐藏类 Hidden Classes
隐藏类是为框架(frameworks)所设计的,隐藏类不能直接被其他类的字节码使用,只能在运行时生成类并通过反射间接使用它们。
该提案通过启用标准 API 来定义 无法发现 且 具有有限生命周期 的隐藏类,从而提高 JVM 上所有语言的效率。JDK内部和外部的框架将能够动态生成类,而这些类可以定义隐藏类。通常来说基于JVM的很多语言都有动态生成类的机制,这样可以提高语言的灵活性和效率。
- 隐藏类天生为框架设计的,在运行时生成内部的class。
- 隐藏类只能通过反射访问,不能直接被其他类的字节码访问。
- 隐藏类可以独立于其他类加载、卸载,这可以减少框架的内存占用。
Hidden Classes是什么呢?
Hidden Classes就是不能直接被其他class的二进制代码使用的class。Hidden Classes主要被一些框架用来生成运行时类,但是这些类不是被用来直接使用的,而是通过反射机制来调用。
比如在JDK8中引入的lambda表达式,JVM并不会在编译的时候将lambda表达式转换成为专门的类,而是在运行时将相应的字节码动态生成相应的类对象。
另外使用动态代理也可以为某些类生成新的动态类。
那么我们希望这些动态生成的类需要具有什么特性呢?
- 不可发现性。 因为我们是为某些静态的类动态生成的动态类,所以我们希望把这个动态生成的类看做是静态类的一部分。所以我们不希望除了该静态类之外的其他机制发现。
- 访问控制。 我们希望在访问控制静态类的同时,也能控制到动态生成的类。
- 生命周期。 动态生成类的生命周期一般都比较短,我们并不需要将其保存和静态类的生命周期一致。
API的支持
所以我们需要一些API来定义无法发现的且具有有限生命周期的隐藏类。这将提高所有基于JVM的语言实现的效率。
比如:
java.lang.reflect.Proxy // 可以定义隐藏类作为实现代理接口的代理类。
java.lang.invoke.StringConcatFactory // 可以生成隐藏类来保存常量连接方法;
java.lang.invoke.LambdaMetaFactory //可以生成隐藏的nestmate类,以容纳访问封闭变量的lambda主体;
普通类是通过调用ClassLoader::defineClass
创建的,而隐藏类是通过调用Lookup::defineHiddenClass
创建的。这使JVM从提供的字节中派生一个隐藏类,链接该隐藏类,并返回提供对隐藏类的反射访问的查找对象。调用程序可以通过返回的查找对象来获取隐藏类的Class对象。
JEP 373: 重新实现 DatagramSocket API
重新实现了老的 DatagramSocket API 接口,更改了 java.net.DatagramSocket 和 java.net.MulticastSocket 为更加简单、现代化的底层实现,更易于维护和调试。

java.net.datagram.Socket
和java.net.MulticastSocket
的当前实现可以追溯到JDK 1.0,那时IPv6还在开发中。因此,当前的多播套接字实现尝试调和IPv4和IPv6难以维护的方式。
- 通过替换 java.net.datagram 的基础实现,重新实现旧版 DatagramSocket API。
- 更改
java.net.DatagramSocket
和java.net.MulticastSocket
为更加简单、现代化的底层实现。提高了 JDK 的可维护性和稳定性。 - 通过将
java.net.datagram.Socket
和java.net.MulticastSocket
API的底层实现替换为更简单、更现代的实现来重新实现遗留的DatagramSocket API。
新的实现:
- 易于调试和维护;
- 与Project Loom中正在探索的虚拟线程协同。
JVM 优化
JEP 373: ZGC: 可伸缩低延迟垃圾收集器
ZGC是Java 11引入的新的垃圾收集器(JDK9以后默认的垃圾回收器是G1),经过了多个实验阶段,自此终于成为正式特性。ZGC是一个重新设计的并发的垃圾回收器,可以极大的提升GC的性能。支持任意堆大小而保持稳定的低延迟(10ms以内),性能非常可观。目前默认垃圾回收器仍然是 G1,后续很有可以能将ZGC设为默认垃圾回收器。之前需要通过
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
来启用ZGC,现在只需要-XX:+UseZGC
就可以。
以下是相关介绍:
ZGC 是一个可伸缩的、低延迟的垃圾收集器,主要为了满足如下目标进行设计:
- GC 停顿时间不超过 10ms
- 即能处理几百 MB 的小堆,也能处理几个 TB 的大堆
- 应用吞吐能力不会下降超过 15%(与 G1 回收算法相比)
- 方便在此基础上引入新的 GC 特性和利用 colord
- 针以及 Load barriers 优化奠定基础
- 当前只支持 Linux/x64 位平台 停顿时间在 10ms 以下,10ms 其实是一个很保守的数据,即便是 10ms 这个数据,也是 GC 调优几乎达不到的极值。根据 SPECjbb 2015 的基准测试,128G 的大堆下最大停顿时间才 1.68ms,远低于 10ms,和 G1 算法相比,改进非常明显。

本图片引用自: The Z Garbage Collector – An Intr