Contents
  1. 1. 改进instanceof的使用方式
  2. 2. 改进的空指针异常
  3. 3. 改进switch语法
  4. 4. 新的字符串使用方式
  5. 5. 移除CMS垃圾收集器
  6. 6. G1垃圾收集器上使用NUMA
    1. 6.1. 什么是NUMA?
    2. 6.2. 什么是G1?
  7. 7. 可以通过流处理的方式读取JFR Event
  8. 8. 支持在MacOS上使用ZGC

本文介绍JDK14新加的几个特性。

改进instanceof的使用方式

JEP 305: Pattern Matching for instanceof (Preview)

这里的Preview指的是预览版本,就是说在下一个版本可能会有进行优化或者修改甚至会有取消的可能。所以暂时还不要全面的使用它,尝鲜即可。

传统的instanceof的使用需要先判断后进行强制类型转换:

1
2
3
4
5
A c = new C();
if(c instanceof C){
C castC = (C) c; // 显示强转后才能使用C类定义的方法
castC.callCMethods();
}

在JDK14中我们可以尝试这样写:

1
2
3
4
5
A c = new C();
if(c instanceof C castC ){
//可以省掉一行代码
castC.callCMethods();
}

改进的空指针异常

JEP 358: Helpful NullPointerExceptions

空指针异常是Java中最让人头疼的异常之一,而且经常发现空指针异常抛出的时候并没有很确切的异常信息告诉我们那个对象的引用导致了空指针异常。JDK14加强了异常的记录机制,通过启用额外的调用记录,可以更加准确的捕获空指针异常抛出的位置:需要在java代码的运行中加上参数 -XX:+ShowCodeDetailsInExceptionMessages 启动这个额外的异常记录机制。比如下面的代码会导致空指针异常抛出(b对象的属性没有赋值)。

1
2
C c = new C();
c.b.a.doA();

传统的空指针异常如下

1
2
Exception in thread "main" java.lang.NullPointerException
at TestJDK14.main(TestJDK14.java:8)

只会告诉你第几行出现了空指针异常,但具体是哪一个对象就不明确了。而JDK14抛出的异常如下:

1
2
Exception in thread "main" java.lang.NullPointerException: Cannot read field "a" because "c.b" is null
at TestJDK14.main(TestJDK14.java:8)

会详细指出出错的位置是c对象的属性b为空。

这个功能在数组的使用上也很实用,如果数组某一个元素为空的话,异常信息会告知哪一个index下的元素为空:

1
2
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "TestJDK14$A.doA()" because "aa[0][1]" is null
at TestJDK14.main(TestJDK14.java:6)

改进switch语法

JEP 361: Switch Expressions (Standard)

这里出现的Standard表示这个版本发布的语法改进是标准版本,经过了大量的测试和完善,基本上不会再有大的改动了,可以放心使用。

Java中的switch语句用在多分支的场景下使用。传统的switch语句看起来是这样的,很长很长。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch (tag){
case "A":
doA();
break;
case "B":
doB();
break;
case "C":
doC();
break;
case "D":
doD();
break;
default:
doNothing();
}

那么在JDK14中我们可以将switch改写为:

1
2
3
4
5
6
7
switch (tag) {
case "A" -> doA();
case "B" -> doB();
case "C" -> doC();
case "D" -> doD();
default -> doNothing();
}

更加好玩的是,我们可以直接将switch赋值给变量或者作为方法的返回结果:

1
2
3
4
5
6
7
return switch (tag) {
case "A" -> doA();
case "B" -> doB();
case "C" -> doC();
case "D" -> doD();
default -> doNothing();
};

新的字符串使用方式

JEP 368: Text Blocks (Second Preview)

这个特性标准为Second Preview指的是前一个版本它已经作为预览版本发布了,现在这个这个版本有所改动,还是作为预览版本发布。这个功能主要是针对字符串输出排版的增强。比如我们想要输入一段文本,包括换行,传统的方法是用\n, 并且用+来格式化代码的显示。

1
2
System.out.println("请关注\n" 
+ "某鸟碎碎");

而在新版本中(应该是从JDK13开始), 下面这个代码也可以输出相同的文本。

1
2
3
4
System.out.println("""
请关注
某鸟碎碎
""");

这个特性还包含了一些对特殊字符的处理,就不在此处赘述了。

JDK从11开始就一直在对字符串处理进行增强。比如增加了灵活选择是去除尾部还是头部空格或者全部空格的strip**系列的方法;比如可以对文本统计行数的String.lines()方法。

移除CMS垃圾收集器

JEP 363: Remove the CMS Garbage Collector

CMS是年老代收集器,基于标记-清除算法实现,是一种以获取最短回收停顿时间为目标的收集器。由于收集完成后会产生碎片,所以可能会在在Full GC之后,进行一次碎片整理,这个整理会导致无法执行并发的工作。在JDK14中你无法使用CMS收集器,即使你强行设定了参数-XX:+UseConcMarkSweepGC, JVM也会自动退回默认的垃圾回收器。

G1垃圾收集器上使用NUMA

JEP 345: NUMA-Aware Memory Allocation for G1

什么是NUMA?

非统一内存访问架构。是为了拥有多个处理器的电脑设计的内存架构,目的就是提高内存的访问速度。而关于NUMA的具体内容,我可能会另开一篇文章(挖坑)。通过使用NUMA,能够改进G1垃圾收集器在大型机(服务器)上的性能。需要添加jvm参数 +XX:+UseNUMA 来启用它。

什么是G1?

G1垃圾回收算法可以说是用来替换CMS的,它是基于标记-整理算法(重点)来实现的,机制是将整个JAVA堆(包括新生代、老年代)划分为多个固定大小的独立区域,并跟踪垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,有限回收垃圾最多的区域。

将 ParallelScavenge + SerialOld 的垃圾回收组合标记为Deprecate

JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination

Deprecate在java中表示该功能不建议使用,并且在未来的版本会移除。官方的解释是这种GC组合很少被使用,并且它们需要繁琐的代码控制。这种GC组合是有其他更优化的可替代方案,所以不再使用他们是没啥影响的。

ParallelScavenge是一种并行的多线程,用于新生代的收集器。

SerialOld是年老代收集器,基于单线程和标记-整理算法。主要是面向客户端单处理器模式。

可以通过流处理的方式读取JFR Event

JEP 349: JFR Event Streaming

什么是JFR?JFR全名JDK Flight Recorder,是对JVM运行数据的记录模块。它包含了超过500项的JVM数据,当然也包括headdump之类传统的分析数据。JFR特性在早前的版本就已经提供,就像我们想获取threaddump或者headdump那样,通过开启JFR,可以得到一个jfr文件,然后再使用jmc相关的工具来分析这个文件。JDK14是增加了一种流处理模式,可以直接在代码中使用RecordingStream这个类直接读取相关JFR记录,实时获取JVM监控信息。好不好用就仁者见仁了。

支持在MacOS上使用ZGC

EP 364: ZGC on macOS

ZGC是什么?是JDK 11中推出的一款低延迟垃圾回收器。它设计的停顿时间不超过10ms并且停顿时间不会随着堆的大小、活跃对象的大小而增加。所以他可以在超大容量的推上使用(目前支持8MB0 - 4TB)。所以在MacOS上运行Java程序的开发者终于可以用上这个看起来很厉害的家伙了,但是我很怀疑,在MacOS真的会有程序运行需要4TB这么多堆内存么?

JDK14 并不是一个长期支持的版本,它应该很快会迭代直到下一个长期支持的版本:JDK17。所以在产品中使用它的话得谨慎考虑,毕竟没有客户想每年都升级一个大版本JDK,然后遇见各种莫名其妙的问题。个人学习玩耍的话可以大胆的使用,毕竟一些新特性自己不主动去学习的话,万一公司要从JDK8升级到JDK17,那需要花费的时间代价可是很大。

Contents
  1. 1. 改进instanceof的使用方式
  2. 2. 改进的空指针异常
  3. 3. 改进switch语法
  4. 4. 新的字符串使用方式
  5. 5. 移除CMS垃圾收集器
  6. 6. G1垃圾收集器上使用NUMA
    1. 6.1. 什么是NUMA?
    2. 6.2. 什么是G1?
  7. 7. 可以通过流处理的方式读取JFR Event
  8. 8. 支持在MacOS上使用ZGC