Jvm+Java+Performance,Java 14 新特性速览,看了都说好!

每天凌晨00点00分, 第一时间与你相约

每日英文

You can't just sit there and wait for life to come to you. You have to go get it.

你不能无所事事的坐等人生带给你一切,你必须得自己努力争取。

每日掏心话

生活总会给你另一个机会,这个机会叫明天。生活没有过去,也没有曾经,不管什么事只要过去了,就会慢慢忘掉。

来自:覃佑桦 | 责编:乐乐

链接:techgeeknext.com/java/java14-features

0900dc87aea7de93ee4dc0c140b14b61.png

程序员小乐(ID:study_tech)第 844 次推文 图片来自百度

往日回顾:手把手教你如何搭建一款自己的私有百度网盘?

正文

Java14发布了!

2020年3月17日,世界上使用最多的编程语言和应用开发平台JavaSE 14及JDK14发布了。Java14发布了大量JEP(Java增强建议)。新版包含的JEP数量甚至比Java12和13的总和还要多。

Java14主要加入了16个新特性(JEP),包括最新的Java API、JDK Fight Recorder监控等等。完整的新特性列表如下:

1. instanceof模式匹配(预览特性)2. 非易失性映射字节缓冲(孵化器)3. 实用的NullPointerException4. 新switch表达式(标准特性)5. 打包工具(孵化器)6. G1中的NUMA内存分配优化7. JFR事件流8. Records(预览特性)9. 弃用Solaris和SPARC端口10. 移除CMS垃圾回收器11. 针对macOS的ZGC(实验特性)12. 针对Windows的ZGC(实验特性)13. 弃用ParallelScavenge+SerialOld GC组合14. 移除Pack200工具和API15. 文本块(第二次预览版)16. 外存访问API(孵化器)

Oracle为所有开发者和企业用户开放了Java14下载。

1. instanceof模式匹配

instanceof操作符用来检查对象引用是否为指定的Type实例,检查的结果使用boolean返回。Java14对instanceof操作符进行了改进,加入了模式匹配。改进后的instanceof让实现逻辑变得清晰,不用在条件判断后再为对象强制类型转换。

Java14以前if (obj instanceof String) {

String str = (String) obj; // 需要再次声明和对象转换

.. str.contains(..)..

}else{

str = ....

}

Java14if (!(obj instanceof String str)) {

.. str.contains(..)..// 不必再声明str对象进行强制类型转换

} else {

.. str....

}

更多示例:if (obj instanceof String str && str.length() > 5) {.. str.contains(..)..}

if (obj instanceof String str || str.length() > 5) {.. str.contains(..)..}

注意:只有object不为null时instanceof才会匹配并把结果分配给str。使用instanceof模式匹配可以减少Java程序中进行强制转换。

2. 非易失性映射字节缓冲(孵化器)

简要地说,JDK1.4开始Java NIO File API就出现了。

FileChannel MappedByteBuffer 该API将部分文件数据加载到虚拟内存中,然后引入了Path特性。Path是一个接口。使用Java NIO开发时,可以用Path替代java.io.File表示文件或目录。

现在,Java 14对MappedByteBuffer进行了改进,将部分文件数据加载到非易失性存储器(NVM)中。NVM非易失性存储是指类似ROM(只读存储器)、闪存、硬盘等存储器,即使关闭电源数据也不会丢失。易失性存储器比如RAM,如果关闭电源则无法保存数据。API唯一的变化是加入了一个新枚举供FileChannel客户端使用。表示请求映射位于NVM支持的文件系统而非传统文件系统。

风险与假设

该特性允许通过ByteBuffer将NVM作为堆外资源进行管理。与此相关的增强功能JDK-8153111正在研究将NVM用于堆数据。可能还会考虑使用NVM存储JVM元数据。不同的NVM管理模式一起使用时也许不兼容,也可能仅仅是不合适。API建议只支持最大2GB映射空间。必要时可以改动实现策略,使其符合,JDK-8180628以突破此限制。

3. 实用的NullPointerException

Java14对JVM生成的NullPointerException异常信息进行了改进。程序提前终止时,新特性将为开发者和技术支持人员提供有用的信息。由于NPE几乎可以出现在程序中的任何位置,尝试捕获它们并从中恢复通常不太可行。开发人员只能靠JVM确认NPE实际的发生时间。例如,假设下面代码抛出一个NPE:a.i = 99;

JVM会输出导致NPE的方法、文件名和行号:Exception in thread "main" java.lang.NullPointerException

at Prog.main(Prog.java:5)

现在假设下面代码抛出一个NPE:a.b.c.i = 99;

仅通过文件名和行号并不能精确指出究竟哪个变量为null。是变量a、变量b还是变量c?

JDK14 JEP改进了异常信息,按照下面的方式抛出该异常,能够确切知道哪个变量为null。Exception in thread "main" java.lang.NullPointerException:

Cannot read field 'c' because 'a.b' is null.

at Prog.main(Prog.java:5)

与此同时也带来一些风险。null详细信息可能包含源代码中的变量名。暴露这些信息可能会带来安全风险。

4. 新switch表达式(标准特性)

Java14扩展了switch语句的功能,可以把switch作为表达式使用。支持箭头(->)操作符生成或返回值。该特性在JDK12和JDK13中是预览功能。

例1Java14以前switch (day) {

case MONDAY:

case FRIDAY:

case SUNDAY:

System.out.println(6);

break;

case TUESDAY:

System.out.println(7);

break;

case THURSDAY:

case SATURDAY:

System.out.println(8);

break;

case WEDNESDAY:

System.out.println(9);

break;

}

Java14

switch (day) {

case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);

case TUESDAY -> System.out.println(7);

case THURSDAY, SATURDAY -> System.out.println(8);

case WEDNESDAY -> System.out.println(9);

}

例2Java14以前

int numLetters;

switch (day) {

case MONDAY:

case FRIDAY:

case SUNDAY:

numLetters = 6;

break;

case TUESDAY:

numLetters = 7;

break;

case THURSDAY:

case SATURDAY:

numLetters = 8;

break;

case WEDNESDAY:

numLetters = 9;

break;

default:

throw new IllegalStateException("Wat: " + day);

}

Java14int numLetters = switch (day) {

case MONDAY, FRIDAY, SUNDAY -> 6;

case TUESDAY -> 7;

case THURSDAY, SATURDAY -> 8;

case WEDNESDAY -> 9;

};

更多示例 // 箭头标签

static void grade(int g) {

System.out.println(

switch (g) {

case 1 -> "A";

case 2 -> "B";

default -> "C";

}

);

}

------------------------------------------

// 生成值-引入新的yield用法

int j = switch (day) {

case MONDAY -> 0;

case TUESDAY -> 1;

default -> {

int d = day.toString().length();

int result = f(d);

yield result;

}

};

5. 打包工具(孵化器)

该特性是一种能够简化安装过流程的打包功能,能解决应用所需的各种依赖项。有时仅提供一个JAR文件是不够的,还需要提供原生安装包。打包工具还可以作为其它技术的补充。

jpackage工具把Java应用打包成平台特定格式的包,其中包含应用所有的依赖项。即一组普通JAR文件或模块的集合。支持的包格式:

1. Linux:deb和rpm2. macOS:pkg和dmg3. Windows:MSI和EXE

6. G1中的NUMA内存分配优化

非一致性内存访问(NUMA)是一种将微处理器集群配置为多处理系统的方式,因此可以在本地共享内存、提高性能并扩展系统能力。Java14实现了NUMA内存分配优化,提升G1在大型计算机上表现。G1中的堆是一组固定大小区域。虽然指定-XX:+UseLargePages选项可以使用大页面,多个区域可以组成一个物理页面,但是一个区域通常是一组物理页面。如果指定+XX:+UseNUMA选项,初始化JVM时上述将把区域平均分布在所有可用NUMA节点上。

7. JFR事件流

Java14提供了一个新的API,JDK Flight Recorder(JFR)可以通过它持续监视进程内与进程外部应用程序。

使用非Stream方式记录相同的事件集,开销可能甚至小于1%。事件流将与非Stream方式同时执行。

jdk.jfr.consumer包位于 jdk.jfr模块中,扩展了异步订阅事件的功能。

8.Record(预览特性)

这是JDK14中一个预览功能。使用record精简类声明代码。

定义一个数据类需要编写很多低效重复的模板代码:构造函数、accessor、equals()、hashCode()、toString()等。Java计划使用record精简这些重复代码。

示例:Java14以前: final class Point {

public final int x;

public final int y;

public Point(int x, int y) {

this.x = x;

this.y = y;

}

// equals、hashCode、toString方法

// 其它什么也没干

Java14使用record record Point(int x, int y) { }

使用record的局限:

· record不能继承其它类,除了描述状态的私有final字段外不能声明其它字段实例。

· record默认为final且不能声明为abstract。这意味着record API完全由状态定定义,不能被其它类或者其它record修改。

· record组件隐式定义为final。

9. 弃用Solaris和SPARC端口

· Java14弃用了Solaris/SPARC、Solaris/x64和Linux/SPARC端口,未来可能将它们移除。

· 取消对这些端口的支持,能让OpenJDK社区的贡献者加速开发新功能,推动平台向前发展。

构建配置变化下面尝试配置Solaris/SPARC $ bash ./configure

...

checking compilation type... native

configure: error: The Solaris and SPARC ports are deprecated and may be removed in a future release.\

Use --enable-deprecated-ports=yes to suppress this error.

configure exiting with result code 1

$

设置--enable-deprecated-port=yes构建选项可以解决错误继续配置。 $ bash ./configure --enable-deprecated-ports=yes

...

checking compilation type... native

configure: WARNING: The Solaris and SPARC ports are deprecated and may be removed in a future release.

...

Build performance summary:

* Cores to use: 32

* Memory limit: 96601 MB

构建Solaris和SPARC版本会报告错误或警告,包括Solaris/SPARC、Solaris/x64、Linux/SPARC。

10. 移除CMS垃圾回收器

Java14删除了CMS垃圾收集器。

不仅停用CMS编译,从源代码中删除了gc/cms目录中的内容,而且删除了仅限CMS的选项。

使用-XX:+UseConcMarkSweepGC选项启用CMS时会提示以下警告: Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; \

support was removed in

虚拟机会继续使用默认垃圾收集器。

11. JEP 364:针对macOS的ZGC(实验特性)

JEP 364实际上和JEP3 65一样。JEP 364针对MacOS提供了ZGC垃圾收集器。它将ZGC垃圾收集器移植到了macOS。正如JEP351中的描述,该JEP的功能还包括使用收集器释放未使用的设备内存。自Java13开始就支持此功能。ZGC的macOS实现包含两个部分:

1. 在macOS上支持多重映射(multi-mapping)内存。

2. ZGC支持不连续预留内存。

12. JEP 365:针对Windows的ZGC(实验特性)

JEP 365实际上和JEP 364一样。JEP 365针对Windows提供了ZGC垃圾收集器支持。

大多数ZGC代码都与平台无关,不需要为Windows修改。由于早期版本没有预留内存必须的API,因此不支持Windows 10和Windows Server 1803之前的版本。

ZGC的Windows实现进行了以下工作:

1. 支持多重映射内存

由于ZGC使用着色指针(colored pointer),因此需要多重映射支持,以便可以从进程地址空间中的多个位置访问相同的物理内存。Windows内存使用分页文件为物理内存提供了一个标识(句柄),与映射的虚拟内存地址无关。ZGC使用该标识可以将相同的物理内存映射到多个地址。

2. 支持将内存映射到预留地址空间,基于分页文件技术。

Windows内存管理API没有POSIX mmap/munmap灵活,当涉及到将文件备份内存映射到之前预留的空间时尤其如此。因此,ZGC使用了Windows地址占位符概念。在Windows 10 V1803和Windows Server中引入了占位符概念。ZGC不支持Windows其它早期版本。

3. 支持堆内存任意区域映射与取消映射操作。

ZGC堆的布局要求支持任意粒度的内存映射和取消映射,以及堆页面动态调整大小与重新调整。此要求与Windows地址空间占位符结合使用时,需要特别注意,因为占位符必须由程序显式拆分/合并,而不是由操作系统自动拆分/合并(与Linux一样)。

4. 支持堆内存任意区域提交和撤销提交操作。

ZGC能在Java程序运行时动态提交和撤销物理内存。为了支持这些操作,物理内存被分为多个分页文件片段。每个片段都对应一个ZGC堆单元,可以独立提交和撤销。

13. JEP 366:弃用ParallelScavenge+SerialOld GC组合

JEP366包含垃圾收集器,它的目标是弃用Parallel Scavenge和Serial Old垃圾收集算法的组合。除了弃用-XX:+UseParallelGC-XX :- UseParallelOldGC组合之外,-XX:UseParallelOld GC选项也被弃用,因为它的作用是取消老年代并行GC,支持老年代串行GC。因此,任何与UseUseParallelOldGC选项有关的用法都会输出警告。

14. JEP 367:移除Pack200工具和API

Pack 200是JavaSE 5.0中JSR 200实现的JAR文件压缩方案。

Java14从java.util.jar包中移除了pack200和unpack200工具以及pack200 API。这些工具和API在JavaSE 11中已废弃,会在随后的版本中移除。该JEP最终会从JDK主版本中移除3种类型。即之前标记 @Deprecated(forRemoval = true) 注解的基础模块:

· java.util.jar.Pack200· java.util.jar.Pack200.Packer· java.util.jar.Pack200.Unpacker

15. JEP 368:文本块(第二次预览版)

在Java中,想要把HTML、XML、SQL或JSON代码片段嵌入到代码中通常难以阅读和保留。并且为了克服此问题,Java14 引入了文本块(Text Block)。

文本块包含零个或多个字符,这些字符由开始分隔符和结束分隔符包围。

没有使用文本块HTML示例 String html = "\n" +

" \n" +

"

Hello, world

\n" +

" \n" +

"\n";

文本块的开始分隔符以三个双引号(""")开始,可以接零个或多个空格,最后是一个换行符。开始分隔符换行后面接着是文本块的内容。

结束分隔符同样是三个双引号。文本块内容在三个双引号之前结束。

与String不同,文本块中可以直接使用双引号。当然也可以使用\" 但不是必需的。选择宽分隔符(""")的好处是可以直接使用"不需要转义,而且能从视觉上把文本块与String进行区分。

文本块是多行String文本。使用文本块能避免大多数转义的情况,支持自动格式化字符串,并且在必要时开发者能自行格式化字符串。

使用文本块的HTML示例 String html = """

Hello, world

""";

2019年初,JEP 355提议把文本块功能作为JEP 326(原始字符串字)的后续改进,随后该提议被撤回。

2019年中,JDK13把文本块作为预览功能加入,接着Java14加入了两个新的转义符。

其一,用\表示换行。其二,是用/s表示一个空格。

换行符示例:// 不使用文本块

String literal = "two escape sequences first is for newlines " +

"and, second is to signify white space " +

"or single space.";

// 使用 \ 看起来像这样:

String text = """

two escape sequences first is for newlines \

and, second is to signify white space \

or single space.\

""";

空白或单空格示例: // 在每行的结尾使用 \s,保证每行的长度为6个字节

String colors = """

aaa\s

bbb\s

ccc\s

""";

16. JEP 370:外存访问API(孵化器)

许多流行的Java库和程序都支持访问外部存储器,例如Ignite、MapDB、Memcached和Netty的ByteBuf API。这样可以避免垃圾回收(比如维护大型缓存)、跨进程共享内存、通过将文件内存映射进行序列化和反序列化(例如mmap)带来的开销以及引入的不可预测性。然而,Java API没有提供适合的外存访问解决方案。

Java14通过JEP 370引入了高效的Java API,使得Java应用程序能够安全有效地访问Java堆外内存。外部存储API提出了三个重要的抽象:MemorySegment、MemoryAddress和MemoryLayout。

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值