☕️从 Java8 到 Java17 的新特性(五):Java13 的新特性
你好,我是看山。
本文收录在 《从小工到专家的 Java 进阶之旅》 系列专栏中。
从 2017 年开始,Java 版本更新策略从原来的每两年一个新版本,改为每六个月一个新版本,以快速验证新特性,推动 Java 的发展。从 《JVM Ecosystem Report 2021》 中可以看出,目前开发环境中有近半的环境使用 Java8,有近半的人转移到了 Java11,随着 Java17 的发布,相信比例会有所变化。
因此,准备出一个系列,配合示例讲解,阐述各个版本的新特性。
概述
本文讲解一下 Java13 的特性,这个版本在语法特性上增加不多,值得关注的是两个预览功能:Switch 表达式和文本块,另外可以关乎的是性能优化方面的:动态类数据共享(CDS)存档、ZGC 动态释放未使用内存、Socket API 重构。这些方面可以看出,Java 的升级方向有两个,一是增加功能,增加新的语法特性;二是增强功能,提升已有功能性能。
预览功能
Java13 引入了两个新的语法特性:Switch 表达式和文本块。这些预览功能是为了让开发者尝鲜的同时,可以快速调整,反馈好就留下,不好就移除。目前来看,这些特性还是挺香的。
Switch 表达式
在 Java12 中 Switch 表达式首次以预览版的身份出现,在 Java13 中又做了增强,在 Java14 正式提供。Java13 添加了yield
关键字,用来返回值。
yield
与return
的区别在于,yield
只会跳出switch
块,return
是跳出当前方法或循环。
比如下面的例子,在 Java12 之前,要判断日期可以这样写:
在 Java12 提供的 Switch 表达式预览功能,我们可以简化一下:
这样可以实现判断,但是没有办法在表达式中实现其他逻辑了。于是 Java13 补齐了这个功能:
这里需要说明一下,既然是预览功能,会与正式提供功能有些出入。上面的代码是在 Java14 环境中编写,与 Java13 发布的功能描述有些差异,这点不必深究,已经废弃的约束就是不存在。
文本块
一直以来,Java 中的字符串定义都是以双引号括起来的形式,不支持多行书写,所以在需要多行字符串中,需要使用转义符表示,既不好看、还不好读,更不好维护。
千呼万唤始出来,终于有了文本块功能。
比如,我们想要写一段 Json 格式的数据,Java13 之前需要写成:
但是在 Java13 预览版中可以写作:
少了很多的+、换行、转移等字符,看着更加直观。
这个功能在 Java15 中正式提供。
动态类数据共享(CDS)存档
CDS 是 Java5 引入的一种类预处理方式,可以将一组类共享到一个归档文件中,借助内存映射加载类数据,减少启动时间,并可实现在多 JVM 之间共享的功能。在 Java10 对其进行扩展,增大了 CDS 使用范围,即 AppCDS(参见 Java10 新特性)。到了 Java12,将 CDS 归档文件作为了默认功能开放出来(参见 Java12 新特性)。
但是这个功能在使用的时候还是有些麻烦。为了生成归档文件,开发人员必须先对应用程序进行试运行,创建一个类列表,然后将其转储到归档文件中。然后,这个归档才可以用来在 JVM 之间共享元数据。
Java13 简化了这个过程:允许 Java 应用在运行结束后动态归档,即将已被加载但不属于 CDS 的类(包括自定义类和引用库的类)动态添加到 CDS 归档文件中。不用再提供归档类的列表,通过更加简洁的方式创建包含应用程序的归档。
我们可以使用-XX:ArchiveClassesAtExit
参数控制应用程序退出时创建 CDS 归档文件:
也可以使用-XX:SharedArchiveFile
来使用动态存档功能:
ZGC 增强:释放未使用内存
ZGC 是 Java11 中引入的一个可伸缩、低延迟的垃圾收集器,主要目标包括:GC 停顿时间不超过 10ms;可以处理从几百 MB 的小堆,到几个 TB 的大堆;应用吞吐能力不会下降超过 15%等(参见 Java11 的新特性)。
但是 ZGC 并没有像 Hotspot 中的 G1 和 Shenandoah 那样,可以主动释放未使用的内存,对于多数应用程序来说,CPU 和内存都是稀缺资源,尤其是现在云上环境和虚拟化技术,如果应用程序占用的内存长期处于空闲状态,还紧握住不释放,就是极大的浪费。
在 Java13 中对其进行改进,包括:
可释放空闲内存
支持的最大堆大小从 4TB 扩大到 16TB
我们来看下 ZGC 的内部逻辑。
ZGC 堆由一组称为 ZPages 的堆区域组成,每个 ZPage 都与提交的堆内存的可变数量相关联。当 ZGC 压缩堆时,ZPages 被释放并插入到页面缓存 ZPageCache 中,页面缓存中的 ZPages 可以重新使用,以满足新的堆分配。
ZPageCache 中的 ZPages 集合代表堆中未使用的部分,这部分可以释放回操作系统。ZPageCache 中的 ZPages 根据 LRU(最近最少使用)排序,并按照大中小进行分组。这样的话就可以根据算法按顺序释放未使用的内存。
Java13 还提供了-XX:ZUncommitDelay=<seconds>
命令,用于指定释放多长时间(默认是 5 分钟)未使用的内存,这个参数类似于 Shenandoah 中的-XX:ShenandoahUncommitDelay=<milliseconds>
。
在 Java13 中,ZGC 内存释放功能默认开启,可通过参数-XX:-ZUncommit
关闭该功能。由于 ZGC 释放内存时,不会低于最小堆内存,即当最小堆内存(-Xms)与最大堆内存(-Xmx)一样时,不会自动释放。
Socket API 重构
Java 中的 Socket 是从 Java1.0 开始就有的,是 Java 中不可或缺的网络 API,算起来已经服役 20 多年了。在这段时间内,信息技术已经发生了很多变化,这些上古 API 有一定的局限性,而且不容易维护和调试。
Java 的 Socket API 主要包括java.net.ServerSocket
和java.net.Socket
,ServerSocket
用来监听连接请求的端口,连接成功后返回的是Socket
对象,可以通过操作Socket
对象实现数据发送和读取。Java 是通过SocketImpl
实现这些功能。
在 Java13 之前,通过SocketImpl
的子类PlainSocketImpl
实现。在 Java13 中,引入NioSocketImpl
实现,该实现以 NIO 为基础,与高速缓冲机制集成,实现非阻塞式网络。
如果想用回PlainSocketImpl
,可以设置启动参数-Djdk.net.usePlainSocketImpl=true
即可。
文末总结
本文介绍了 Java13 新增的特性,完整的特性清单可以从https://openjdk.java.net/projects/jdk/13/查看。后续内容会发布在 从小工到专家的 Java 进阶之旅 系列专栏中。
青山不改,绿水长流,我们下次见。
推荐阅读
你好,我是看山。游于码界,戏享人生。如果文章对您有帮助,请点赞、收藏、关注。
版权声明: 本文为 InfoQ 作者【看山】的原创文章。
原文链接:【http://xie.infoq.cn/article/5d794768be89784b1c2e37dcf】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论