乐趣区

关于java:Java-16中的67个新功能

摸索 Java 16 提供的性能。

时光飞逝!即便在这样的不凡期间,仿佛也很难置信曾经过来了六个月,当初咱们有了 JDK 的新版本。像平常一样,我将总结所有新性能,并对它们对 Java 利用程序开发的潜在影响进行一些评论。

并非所有版本都是雷同的,并且取决于性能开发阶段的对齐形式。一些将比其余具备更多的性能。JDK 16 蕴含了许多新内容,只管其中一些是孵化器模块的连续或实现,或者是较早版本的预览性能。我认为这是更快公布节奏的最大益处之一。提供新性能而不使其成为规范的一部分,收集开发人员的反馈,并可能进行更改,这些都为 JDK 开发提供了改良的过程。

我将采纳通常的办法将帖子分为语言更改,库增加,与 JVM 相干的更新,以及其余所有内容。

Java 语言

JDK 16 中没有新的语法结构,然而依然存在一些重大变动。

JEP 394:instanceof 的模式匹配

这是在 JDK 14 中作为预览性能引入的,并在 JDK 15 中以预览模式持续进行。此性能已在 JDK 16 中实现。它蕴含在 Java SE 16 语言标准中,不须要–enable-preview 命令行标记即可进行编译和运行。

该性能在 JDK 15 中的工作形式有两个小变动。首先是模式变量不再隐式最终。这是十分合乎逻辑的更改,因为未将局部变量视为隐式最终变量。

第二个变动是当初是表达式模式 instanceof 的编译时谬误,该表达式实例将类型 S 的表达式与类型 T 的模式进行比拟,其中 S 是 T 的子类型。这是一个例子:

var a = new ArrayList<String>();
if (a instanceof List l)

System.out.println(l.size());

这将导致编译器谬误:

Error: pattern type java.util.List is a subtype of expression type

java.util.ArrayList<java.lang.String>

这仿佛是合乎逻辑的,因为 if 语句是多余的,因为该谓词始终会评估为 true。

JEP 395:记录

JDK 14 中引入的另一个预览性能现已在 JDK 16 中实现。对我来说,这是对 Java 语言的无益补充,因为咱们终于有了一种解决元组的简略办法。

JDK 15 实现对 Records 的惟一更改是放宽了长期的限度,即外部类不能声显著式或隐式动态的成员。这对于简化某些流操作十分有用。通常,心愿每个元素的流都通过一个以上的对象。当初,能够定义本地记录,以缩小原本会导致的类型净化。

JEP 397:密封类

此性能是在 JDK 15 中作为预览性能引入的,并在 JDK 16 中持续作为预览性能。

有三处更改:

增加新的语言语法通常须要新的关键字。将这些作为保留字增加到语言中(例如 JDK
1.4 中的 assert)会重大影响向后兼容性,因为这些字不再可用作标识符。咱们曾经有了限度类型和限度关键字(例如 var 和 seal)的概念来解决此问题。该 JEP 引入了上下文关键字的概念。具体来说,对于 JDK
16,密封,非密封和容许是上下文关键字。
与匿名类和 lambda 表达式一样,在确定密封类或接口的隐式申明的容许子类时,部分类可能不是密封类的子类。
JLS 中变窄的参考转换定义已扩大为在密封的层次结构中导航,以确定在编译时无奈进行哪些转换。

类库

通过各个 JEP 定义了四个新库:

JEP 338:矢量 API

不要与 collections API 中不举荐应用的 Vector 类混同,这是一个使开发人员可能更好地应用根底 CPU 向量性能的库。所有古代处理器都具备单指令多数据(SIMD)性能。阵列的多个元素能够加载到十分宽的寄存器中,例如特定 Intel 处理器上的 512 位 AVX-512。例如,能够在单个机器指令周期内执行将每个值加 10 的单个操作,从而显着进步数字密集型代码的性能。问题在于,编译器须要辨认能够转换为向量运算的代码,这可能十分艰难,尤其是在波及条件运算的状况下。

向量 API 为开发人员提供了一种机制,可向编译器明确表明应应用向量操作。然而,这的确使代码更加简单。首先,有必要取得一种载体。无论是要应用的寄存器大小还是要加载的数据类型(例如浮点数),这都是所需的向量模式。而后创立特定于类型的向量,并依据须要将其装入值。最初一部分是应用适当的数学函数来操纵向量。

所有这些都能够在从 JEP 提起的示例中看到。

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);
}

}

它是作为孵化器模块提供的,因而在蕴含在 Java SE 规范中之前可能会有所更改。我心愿开发人员将意识到应用缩写是不必要的(或现实的)。我宁愿看到 mulple(),而不是 mul(),依此类推。

JEP 380:UNIX 域套接字通道

UNIX 域套接字曾经存在了很长时间,可追溯到 1983 年的 BSD 变体。然而,直到 2018 年,它们才在 Windows 平台中引入。因为 Java 以跨平台为荣,因而领有一个无奈在任何中央运行的库没有多大意义。

当初,咱们有了 UNIX 域套接字 API,该 API 提供了一种在单个主机上解决过程间通信的简便办法。这些套接字与应用 TCP / IP 环回十分类似,只不过它们是通过文件系统路径名而不是 IP 地址和端口号来寻址的。UNIX 域套接字的长处是它们比回送更为无效和平安。

JEP 393:内部内存拜访 API

该库在 JDK 14 中作为孵化器模块引入,在 JDK 16 中是其第三次迭代。

该 API 容许 Java 程序平安无效地拜访 Java 堆内部的内部内存。它与 Project Panama 无关,该我的项目旨在取代 Java 本机接口,以使 Java 应用程序与本机库进行交互。

JDK 15 孵化器版本有四个更改:

MemorySegment 和 MemoryAddress 接口之间的角色更加清晰地拆散。

一个新的接口 MemoryAccess,提供了常见的动态内存拜访器,以在简略状况下将对 VarHandle API 的需要降至最低。

反对共享细分。

向清理器注册段的能力

JEP 389:内部链接器 API

作为孵化器模块,它引入了一个 API,该 API 提供了对本地代码的动态类型的纯 Java 拜访。这也是 Project Panama 的一部分,并且与 Foreign Memory Access API 联合应用,使绑定到本地库变得更加简略。最后的实现侧重于用 C 编写的库。

首先必须在库中找到适当的符号,能力与外来性能进行交互。LibraryLookup 接口用于实现此操作,能够通过 java.library.path 上的库或应用显式文件门路从 JVM 中加载的符号中找到符号。

找到了要应用的内部函数之后,Clinker 接口提供了两种在 Java 代码和函数之间进行交互的办法:

downcallHandler 办法返回一个 MethodHandle,该办法可用于以与 Java 办法雷同的形式调用内部函数。
upCallStub 办法返回一个 MemorySegment(来自内部存储器拜访 API)。当内部函数须要回调 Java 办法(通常作为回调办法)时应用它。
当您查看应用内部链接器 API 的示例时,代码仿佛非常复杂。巴拿马我的项目蕴含 jextract 工具,该工具尚未蕴含在 JDK 中。通过删除所有样板代码并容许简略的动态导入来拜访内部函数,这大大简化了事件。心愿这将使它成为 JDK 17。

其余 API 变更

更新的 Java SE 标准中包含 58 个新的 API 元素,包含上述的 UNIX 域套接字。以下是我认为对开发人员乏味的其余一些内容。

java.lang

在 Class 中,allowedSubClasses()已替换为 getPermittedSubClasses()。

IndexOutOfBoundsException 当初具备一个新的构造函数,该构造函数须要很长时间能力解决索引所援用的索引大于 int 的状况。

java.nio

ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer 和 ShortBuffer 都有一个新的 put()办法。这些办法从第二个缓冲区的给定偏移量开始复制第二个缓冲区的定义长度局部,到该办法被调用的缓冲区中的指定索引。该形容仿佛很简单,然而它是循环的简略代替:

for (int i = offset, j = index; i < offset + length; i++, j++)

destinationBuffer.put(j, sourceBuffer.get(i));

java.time.format

DateTimeFormatterBuilder 类具备一个新办法 appendDayPeriodText()。这提供了一种将一天中的工夫格式化为“上午”,“下午”等的形式,而不仅仅是 AM 或 PM

javax.swing

很快乐看到 Swing 仍在获取更新,即便它们很小。

JPasswordField 有一个新办法 setText()。如果您想用曾经记住的明码字段事后填充明码字段,这将很有用(这是我解决网站登录凭据的惟一办法)。
AccessibleJSlider 有一个新的侦听器 stateChanged()
java.util.logging

LogRecord 有两个新办法,即 getLongThreadID()和 setLongThreadID()。这些是当初不倡议应用的 get / setThreadID 办法的代替办法,该办法限于整数值。

JDK 16 中的流 API 进行了一些激动人心的更改。

首先是在 Stream 接口上蕴含作为默认办法提供的新终端操作。这是 toList(),它将流中的元素累积到不可批改的列表中。使列表不可批改已促使在 Reddit 之类的中央进行了一些探讨,但这仿佛是合乎逻辑的抉择。

第二个变动是引入 mapMulti()作为两头操作,再次作为流上的一组默认办法提供(这包含针对 double,int 和 long 的特定于类型的办法)。当您第一次浏览此操作的阐明时,它看起来与 flatMap 雷同。它返回一个流,该流包含用多个元素(特地是零个或多个元素)替换此流的每个元素的后果。与 flatMap()无效地连贯输出流中每个元素生成的流不同,mapMulti()利用映射能够导致生成多个元素。如果要应用 mapMulti()映射到零个或一个元素,则它与过滤操作雷同。如果应用它仅映射到一个元素,则它将与 map()雷同。益处是当您要为每个输出元素创立多个元素时。一个简略的示例如下所示:

`wordList.stream()

.mapMulti((str, consumer) -> {for (int i = 0; I < str.length(); i++)
        consumer.accept(str.length());
    })
.forEach(System.out::print);`

对于单词流,后果将是每个单词的长度打印该次数。这里重要的是,能够依据须要屡次调用使用者上的 accept()办法。

JDK 16(javax.tools.ToolProvider 类的构造函数)中仅删除了一个先前不举荐应用的 API。

JVM 相干性能

JEP 376 将 ZGC 线程堆栈解决从平安点移至并发阶段,即便在大型堆上,也能够大大减少 GC 平安点外部的暂停。ZGC 的初始阶段(与许多收集器一样)建设了应用程序可拜访的对象的根汇合。为此,须要遍历堆栈以查找对象援用。过来,这要求所有线程都达到全局平安点,在该点上,所有线程都能够平安地暂停并实现工作。在 ZGC 中,这不再是必须的,能够与应用程序线程同时实现。乏味的是,此设计形式并未将其绑定到 ZGC,因而 Shenandoah 我的项目也抉择应用此性能。

元空间是永恒代的代替,永恒代已经蕴含在堆中。JEP 387 引入了弹性元空间,其中应用的内存能够更迅速地返回操作系统。该代码也失去了简化,从而缩小了保护开销。

其余 JDK 性能

多年来,OpenJDK 我的项目根底构造最重大的变动是从 Mercurial 到 Git 的 OpenJDK 源代码管理系统(JEP 357)迁徙,并将所有代码托管在 Github(JEP 369)上。Git / Github 在开发人员中十分受欢迎,因而这是一个理智的决定,它将帮忙吸引更多的人参加该我的项目。

与 JVM 源代码也特地相干的是容许应用 C ++ 14 性能(JEP 347)的行动。仿佛应用更新的语言性能的确步履蹒跚,因为咱们当初才包含应用已有七年历史的性能。设想一下这会给 JVM 开发人员带来的兴奋,他们当初能够应用二进制文字了!

JDK 有两个新的端口,从 JDK 16 开始:

平地 Linux(JEP 386):这次要针对心愿部署基于 Java 的微服务的用户。Alpine
Linux 应用 C 库的 Musl 实现来提供起码的 Linux 环境。联合应用 jlink 生成的 JDK,Docker 映像可小至 38Mb。诚然,这仅包含 java.base 模块,但这是一个很好的终点。
Windows / AArch64(JEP 388):Arm
64 处理器在服务器端和客户端都变得越来越风行。此端口将有助于进一步提高 Java 的风行度。从一开始就参加 Java,我必须说,很快乐看到 Microsoft 为 OpenJDK 我的项目做出了奉献!

Valhalla 我的项目心愿将值类型带入 Java,在交付 Java 之前,须要对 Java 进行一些轻微的更改。当初将现有的原始包装器类(例如 Integer)指定为基于值的类,并且不倡议应用构造函数将其删除。通常,无论如何都不会应用它们,然而如果您应用了它们,则会收回适当的编译器正告。如果尝试在这些类的实例上进行同步,还将生成正告音讯。JEP 390 中对此进行了具体阐明。

JDK 9 引入了 Java Platform Module System,其中一个必然的局部是 JEP 260,它封装了 JDK 的大多数外部 API。因为这有可能毁坏许多现有代码,所以蕴含了一个命令行标记:–illegal-access,它能够具备以下四个值之一:allow,warn,debug 和 deny。从 JDK 9 开始,默认值是容许的,从而容许应用要害外部 API 的代码持续按预期运行。在 JDK 16 中,感激 JEP 396,默认状况下,JDK 外部 API 严格封装(将标记值更改为回绝)。JEP 申明这将不会封装尚不存在规范替代品的 API。这意味着 sun.misc.Unsafe 将放弃可用。当初,一些在 JDK 15 中生成正告的反射代码将引发异样并终止,因而请小心!

只管尚未失去确认,但在 JDK 17 中仿佛不再可能放松封装,从而无效地删除了–非法拜访标记。

包装工具

在 JDK 11 之前,Oracle 将 JavaFX 蕴含在其 JDK 构建中。这提供了一个不错的工具,能够为 Java 应用程序生成可装置的,特定于平台的软件包。删除此性能后,开发人员示意心愿复原此性能。它作为孵化器模块蕴含在 JDK 14 中(只管不是确切的模块,但孵化器也涵盖了工具)。当初,它已作为残缺性能蕴含在 JDK 16 中。与 JDK 14 相比,惟一的变动是将–bind-services 命令行标记替换为更通用的–jlink-options 标记。

JDK 中删除了两个试验性能,特地是 Graal JIT 编译器和提前工具 jaot。据揣测,这是因为 Oracle 正在投资并推广包含此性能的 GraalVM。

论断

JDK 16 持续了 Java 平台的疾速变更步调。咱们真的开始看到预览性能和孵化器模块的性能和劣势。

应用 JDK 17,咱们将看到下一个长期反对版本。只管这不是 OpenJDK 的概念,但它是所有 OpenJDK 二进制发行版(包含 Azul 的 Zulu)提供程序所提供的。因而,您相对应该应用 JDK 16 测试您的应用程序,以查看这些更改是否有任何影响。

您筹备好应用古代 Java 了吗?

(留神:我计算了 67 个新性能和 API,其中包含 17 个 JEP 和 50 个新 Java SE API 元素。UNIX 域套接字占 8 个 API 元素)。

参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://blog.csdn.net/weixin_…

退出移动版