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

Java 14 新特性速览,看了都说好

程序员小乐(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。


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


猜你还想看


阿里、腾讯、百度、华为、京东最新面试题汇集

5万字长文!SpringBoot 操作 ElasticSearch 详解

关于 MyBatis 我总结了 10 种通用的写法

分布式事务之 RocketMQ 事务消息详解

关注订阅号「程序员小乐」,收看更多精彩内容
嘿,你在看吗?


分享到:


相關文章: