写点什么

☕️从 Java8 到 Java17 的新特性(八):Java15 的新特性

作者:看山
  • 2022 年 5 月 17 日
  • 本文字数:5894 字

    阅读完需:约 19 分钟

☕️从 Java8 到 Java17 的新特性(八):Java15 的新特性

你好,我是看山。


本文收录在 《从小工到专家的 Java 进阶之旅》 系列专栏中。


从 2017 年开始,Java 版本更新策略从原来的每两年一个新版本,改为每六个月一个新版本,以快速验证新特性,推动 Java 的发展。从 《JVM Ecosystem Report 2021》 中可以看出,目前开发环境中有近半的环境使用 Java8,有近半的人转移到了 Java11,随着 Java17 的发布,相信比例会有所变化。


因此,准备出一个系列,配合示例讲解,阐述各个版本的新特性。

概述

Java15 是在 2020 年 9 月发布的一个短期版本,新增特性如下:


  • JEP 339:Edwards-Curve 数字签名算法

  • JEP 360:密封的类和接口(预览功能)

  • JEP 371:隐藏类

  • JEP 372:移除 Nashorn JavaScript 引擎

  • JEP 373:重新实现 DatagramSocket 接口

  • JEP 374:禁用偏向锁

  • JEP 375:instanceof 匹配模式(第二版预览功能)

  • JEP 377:ZGC:可伸缩低延迟垃圾收集器

  • JEP 378:文本块

  • JEP 379:Shenandoah:低暂停时间垃圾收集器

  • JEP 381:移除 Solaris 和 SPARC 端口 API

  • JEP 383:外部存储器访问 API(第二版孵化功能)

  • JEP 384:Record 类型(第二版预览功能)

  • JEP 385:废除 RMI Activation


接下来我们一起看看这些特性。

Edwards-Curve 数字签名算法(JEP 339)

Edwards-Curve 数字签名算法(EdDSA),一种根据 RFC 8032 规范所描述的 Edwards-Curve 数字签名算法(EdDSA)实现加密签名。


EdDSA 是一种现代的椭圆曲线方案,与 JDK 中的现有签名方案相比,EdDSA 具有更高的安全性和性能,因此备受关注。它已经在 OpenSSL 和 BoringSSL 等加密库中得到支持,目前在区块链领域用的比较多。


我们看下官方给的例子:


byte[] msg = "Hello, World!".getBytes(StandardCharsets.UTF_8);
// example: generate a key pair and signKeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519Signature sig = Signature.getInstance("Ed25519");sig.initSign(kp.getPrivate());sig.update(msg);System.out.println(Hex.encodeHexString(sig.sign()));
// example: use KeyFactory to contruct a public keyKeyFactory kf = KeyFactory.getInstance("EdDSA");NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdECPoint(true, new BigInteger("1")));PublicKey pubKey = kf.generatePublic(pubSpec);System.out.println(pubKey.getAlgorithm());System.out.println(Hex.encodeHexString(pubKey.getEncoded()));System.out.println(pubKey.getFormat());
复制代码


例子中 Ed25519 是使用 SHA-512(SHA-2)和 Curve25519 的 EdDSA 签名方案。旨在提供与高质量 128 位对称密码相当的抗攻击能力,公钥长度为 256 位,签名长度为 512 位。

隐藏类(JEP 371)

Java15 引入了一个新的特性:隐藏类(Hidden Classes),一个专为框架而设计的特性。大多数开发人员不会直接使用这个特性,一般是通过动态字节码或 JVM 语言来使用隐藏类。


隐藏类有下面三个特点:


  1. 不可发现:在运行时生成内部类对象;

  2. 访问控制:只能通过反射访问,不能直接被其他字节码访问;

  3. 较短的生命周期:可独立于其他类加载、卸载,且效率很高,能够减少框架的内存占用。


隐藏类的功能特性还是比较有意思的,会涉及类加载、卸载、不可见、反射等很多内容,后续会开文单独聊,文章会放在 从小工到专家的 Java 进阶之旅 专栏中。

重新实现 DatagramSocket 接口(JEP 373)

老的 DatagramSocket API 在 Java15 中被重写,是继 Java14 重写 Socket API 的后续不走。这个特性是 Loom 项目的先决条件。


目前,DatagramSocketMulticastSocket将所有的套接字委托为java.net.DatagramSocketImpl的实现,根据不同的平台,Unix 平台使用PlainDatagramSocketImpl,Windows 平台使用TwoStackPlainDatagramSocketImplDualPlainDatagramSocketImpl。抽象类DatagramSocketImpl是 Java1.1 提供的,功能很少且有一些过时方法,阻碍了 NOI 的实现。


类似于 Java14 中对 Socket API 的重写(参见 Java14 新特性),会在DatagramSocket内部封装一个DatagramSocket实例,将所有调用直接委托给该实例。包装实例或者使用 NIO 的DatagramChannel::socket创建套接字,或者是使用原始DatagramSocket类的实现DatagramSocketImpl实现功能(用于实现向后兼容)。


我们可以看下新的依赖图:


禁用偏向锁(JEP 374)

在 Java15 中,默认禁用偏向锁,弃用了所有相关命令行选项。


偏向锁是 HotSpot 中一种用于减少非竞争锁定开销的优化技术,不过在如今的应用程序中,优化增益不太明显了。


根据官方说法,使用偏向锁增益最多的是大量使用早期同步组件(比如HashtableVector等),随着新的 API 实现和针对多线程场景引入的支持并发的数据结构,偏向锁的锁定及撤销,会带来性能的开销,从而是优化收益降低。


而且随着越来越多的功能特性引入,偏向锁在同步子系统中引入的大量代码,侵入 HotSpot 其他组件,带来代码的复杂性和维护成本,成为代码优化的阻碍。所以官方要将其移除。


不过,有些应用在禁用偏向锁后会出现性能下降,可以使用-XX:+UseBiasedLocking手动开启。

ZGC:可伸缩低延迟垃圾收集器(JEP 377)

ZGC 是在 Java11 引入的(参见 Java11 新特性),一直处于试验阶段,想要体验,需要在参数中使用-XX:+UnlockExperimentalVMOptions -XX:+UseZGC组合启用,在 Java15 中,ZGC 成为正式特性,想要使用可以直接用命令-XX:+UseZGC就行。


ZGC 是一个重新设计的并发的垃圾回收器,可以极大的提升 GC 的性能,支持任意堆大小而保持稳定的低延迟。从 https://openjdk.java.net/jeps/333 给出的数据可以看出来,在 128G 堆大小的测试中,ZGC 优势明显,找了一张网上的图片:



虽然 ZGC 愿景很好,但是还有很长的路要走,所以默认的垃圾收集器还是 G1。

Shenandoah:低暂停时间垃圾收集器(JEP 379)

Shenandoah 是在 Java12 引入的(参见)Java12 的新特性,本次和 ZGC 一起转正。同样的,想要使用 Shenandoah,不再需要参数-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC组合,只使用-XX:+UseShenandoahGC即可。需要注意的是,Shenandoah 只在 OpenJDK 中提供,OracleJDK 中并不包含。

文本块(JEP 378)

文本块是千呼万唤终于转正,在 Java13 中首次引入(参见 Java13 的新特性),在 Java14 中又增加了预览特性(参见 Java14 的新特性),终于在 Java15 确定下来,可以放心使用了。


我们再复习一下:


@Testvoid testTextBlock() {    final String singleLine = "你好,我是看山,公众号「看山的小屋」。这行没有换行,而且我的后面多了一个空格 \n 这次换行了";    final String textBlockSingleLine = """            你好,我是看山,公众号「看山的小屋」。\            这行没有换行,而且我的后面多了一个空格、s            这次换行了""";
Assertions.assertEquals(singleLine, textBlockSingleLine);}
复制代码


这个功能特性是代码可读性的优化。

预览

密封类和接口(JEP 360)

目前,Java 没有提供对继承的细粒度控制,只有 public、protected、private、包内控制四种非常粗粒度的控制方式。


为此,密封类的目标是允许单个类声明哪些类型可以用作其子类型。这也适用于接口,并确定哪些类型可以实现它们。该功能特性新增了sealednon-sealed修饰符和permits关键字。


我们可以做如下定义:


public sealed class Person permits Student, Worker, Teacher {}
public sealed class Student extends Person permits Pupil, JuniorSchoolStudent, HighSchoolStudent, CollegeStudent, GraduateStudent {}
public final class Pupil extends Student {}
public non-sealed class Worker extends Person {}
public class OtherClass extends Worker {}
public final class Teacher extends Person {}
复制代码


我们可以先定义一个sealed修饰的类Person,使用permits指定被继承的子类,这些子类必须是使用finalsealednon-sealed修饰的类。其中Student是使用sealed修饰,所以也需要使用permits指定被继承的子类。Worker类使用non-sealed修饰,成为普通类,其他类都可以继承它。Teacher使用final修饰,不可再被继承。


从类图上看没有太多区别:



但是从功能特性上,起到了很好的约束作用,我们可以放心大胆的定义可以公开使用,但又不想被非特定类继承的类了。

instanceof 模式匹配-预览第二版(JEP 375)

instanceof 模式匹配首先在 Java14 中提供预览功能(参见 Java14 特性),可以提供instanceof更加简洁高效的实现,在 Java15 中没有新增特性,主要是为了再次收集反馈,根据结果看,大家还是很期待这个功能,在 Java16 中正式提供。


我们再简单看下instanceof的改进:


@Testvoid test1() {    final Object obj1 = "Hello, World!";    int result = 0;    if (obj1 instanceof String str) {        result = str.length();    } else if (obj1 instanceof Number num) {        result = num.intValue();    }
Assertions.assertEquals(13, result);}
复制代码

Record 类型-预览第二版(JEP 384)

Record 类型用来增强 Java 语言特性,充当不可变数据载体。在 Java14 中提供预览功能(参见 Java14 新特性),在 Java15 中提供第二次预览,这次预览的目标是收集用户反馈。


比如,我们定义一个Person类:


public record Person(String name, String address) {}
复制代码


我们转换为之前的定义会是一坨下面这种代码:


public final class PersonBefore14 {    private final String name;    private final String address;
public PersonBefore14(String name, String address) { this.name = name; this.address = address; }
public String name() { return name; }
public String address() { return address; }
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } PersonBefore14 that = (PersonBefore14) o; return Objects.equals(name, that.name) && Objects.equals(address, that.address); }
@Override public int hashCode() { return Objects.hash(name, address); }
@Override public String toString() { return "PersonBefore14{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; }}
复制代码


Record 类型特性有四个特性:


  1. 设计一个面向对象的结构,表达简单的信息聚合;

  2. 帮助开发人员专注于建模不可变数据,而不是可扩展的行为;

  3. 自动实现数据驱动的方法,比如equalsgettersetter等方法;

  4. 保留长期存在的 Java 规范,比如迁移兼容性。


我们不能将 Record 类型简单的理解为去除“样板化”代码的功能,它不是解决 JavaBean 命名约定的中很多模板化方法的冗余繁杂问题,它的目标不是类似 Lombok 等工具自动生成代码的功能,是从开发人员专注模型的角度出发的。

孵化

外部存储器访问 API-孵化第二版(JEP 383)

外部存储器访问 API 在 Java14 开始孵化(参见 Java14 新特性),在 Java15 中继续孵化状态,这个版本中增加了几个特性:


  • 新的VarHandleAPI,用于定制内存访问句柄;

  • 支持Spliterator接口实现并行处理内存段;

  • 增强了对映射内存段的支持;

  • 能够像本机调用一样操作或间接操作内存地址。


外部内存通常是说那些独立 JVM 之外的内存区域,可以不受 JVM 垃圾收集的影响,通常能够处理较大的内存。


这些新的 API 虽然不会直接影响多数的应用类开发人员,但是他们可以在内存的第三方库中提供支持,包括分布式缓存、非结构化文档存储、大型字节缓冲区、内存映射文件等。

其他

移除 Nashorn JavaScript 引擎(JEP 372)

Nashorn JavaScript 引擎最初在 Java8 中引入(参见 Java8 新特性),在 Java11 被标记为过期,在 Java15 中被删除,包括 Nashorn JavaScript 引擎、API、jjs 工具等内容。


Nashorn JavaScript 引擎是一个 JavaScript 脚本引擎,用来取代 Rhino 脚本引擎,对 ECMAScript-262 5.1 有完整的支持,增强了 Java 和 JavaScript 的兼容性,而且有很强的性能。


随着 GraalVM 和其他虚拟机技术最近的引入,Nashorn 引擎不再在 JDK 生态系统中占有一席之地。而且,ECMAScript 脚本语言结构、API 改变速度太快,Nashorn JavaScript 引擎维护成本太高,所以,直接删了。

移除 Solaris 和 SPARC 端口 API(JEP 381)

Solaris 和 SPARC 都已被 Linux 操作系统和英特尔处理器取代。放弃对 Solaris 和 SPARC 端口的支持将使 OpenJDK 社区的贡献者能够加速开发新功能,从而推动平台向前发展。


Solaris 和 SPARC 端口 API 在 Java14 中标记过时,在 Java15 中彻底移除。仅仅半年就痛下杀手,可见社区对于维护这些 API 深受折磨。

废除 RMI Activation(JEP 385)

RMI Activation 在 Java15 中标记为废除,会在未来版本删除。之所以被删除,是因为在现代的 web 应用中,已经不需要这种激活机制,继续维护,增加了 Java 开发人员的维护负担。在 Java8 的时候,已经将其设置为非必选项。


从开发系统的角度看,虽然 RMI Activation 是一个还不错的设计,但是已经有其他替代方案,继续维护开发下去,成本收益完全不匹配,及早舍弃,可以选择更加优秀的方案。有些类似于零边际成本的思想。

文末总结

本文介绍了 Java15 新增的特性,完整的特性清单可以从 https://openjdk.java.net/projects/jdk/15/ 查看。后续内容会发布在 从小工到专家的 Java 进阶之旅 系列专栏中。


青山不改,绿水长流,我们下次见。

推荐阅读


你好,我是看山。游于码界,戏享人生。如果文章对您有帮助,请点赞、收藏、关注。

发布于: 刚刚阅读数: 3
用户头像

看山

关注

🏆 InfoQ写作平台-签约作者 🏆 2017.10.26 加入

InfoQ签约作者,CSDN 博客专家,公号「看山的小屋」,专注后端开发、架构相关知识分享,个人网站 https://howardliu.cn/。

评论

发布
暂无评论
☕️从 Java8 到 Java17 的新特性(八):Java15 的新特性_Java_看山_InfoQ写作社区