摸索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_...