2020 年 3 月 17 日,JDK / Java 14 正式 GA(General Available)。这是自从 Java 采用六个月一次的发布周期之后的第五次发布。
此版本包含的 JEP Java/JDK Enhancement Proposals JDK 增强提案)比 Java 12 和 13 加起来的还要多。总共 16 个新特性,包括两个孵化器模块 、三 个预览特性、两个弃用的功能以及两个删除的功能。
安装 JDK 14 https://www.oracle.com/technetwork/java/javase/overview/index.html
安装编译器: IDEA 2020.1 或者 Eclipse 2020-03
这个特性很有意思,因为它为更为通用的模式匹配打开了大门。模式匹配通过更为简便的语法基于一定的条件来抽取对象的组件,而 instanceof 刚好是这种情况,它先检查对象类型,然后再调用对象的方法或访问对象的字段。
在 Java 14 之前,我们使用 instanceof 是这样的
@Test public void test01() { Object obj = "hello java14"; if (obj instanceof String) { String str = (String) obj; System.out.println(str.contains("hello")); } else { System.out.println("不是 String 类型"); } }
在 Java 14 中是这样的,相当于将上面的第4、5行代码简化了,省略了强制转化的过程,注意:「str 的作用域依旧是 if 结构内」
@Test public void test02() { Object obj = "hello java14"; if (obj instanceof String str) { System.out.println(str.contains("hello")); } else { System.out.println("不是 String 类型"); } }
有了该功能, 可以减少 Java 程序中显式强制转换的数量 ,从而提高生产力,还能实现更精确、简洁的类型安全的代码 。
该特性改进了 NullPointerException 的可读性,能更准确地给出 null 变量的信息 。
就是这个老爷子当年发明的 null,让成千上万的程序员深恶痛绝,他称自己犯了一个价值十亿美金的错误,那就是空指针!
《Java 8 实战》中是这样说的:
在 Java 8 中引入了 Optional,Optional 在可能为 null 的对象上做了一层封装,强制你思考值不存在的情况,这样
就能避免潜在的空指针异常 。
在 Java 14 中,对于 NPE 有了一个增强,该特性可以更好地提示哪个地方出现的空指针
需要我们在运行参数上加上 -XX:+ShowCodeDetailsInExceptionMessages
开启此功能,这个增强特性不仅适用于方法调用,只要会导致 NullPointerException 的地方也都适用,包括字段的访问、数组的访问和赋值 。
我们有时候需要编写许多低价值的重复代码来实现一个简单的数据载体类:构造函数,访问器,equals()、hashCode()、toString() 等。为了避免这种重复代码,Java 14 推出了 record 。
该预览特性提供了一种更为紧凑的语法来声明类。 值得一提的是,该特性可以大幅减少定义类似数据类型时所需的样板代码。
使用 record 来减少类声明语法,效果类似 lombok 的 @Data 注解, Kotlin 中的 data class 。它们的共同点是 类的部分或全部状态可以直接在类头中描述 ,并且这个类中只包含了纯数据而已。
我们声明一个 record 类型的类
public record Person(String name, Integer age) { }
它编译后的 class 文件如下
public final class Person extends java.lang.Record { private final java.lang.String name; private final java.lang.Integer age; public Person(java.lang.String name, java.lang.Integer age) { /* compiled code */ } public java.lang.String toString() { /* compiled code */ } public final int hashCode() { /* compiled code */ } public final boolean equals(java.lang.Object o) { /* compiled code */ } public java.lang.String name() { /* compiled code */ } public java.lang.Integer age() { /* compiled code */ } }
调用其属性的时候与普通类有所不同
@Test public void test3(){ Person person = new Person("张三", 12); person.name(); person.age(); }
当你用 record 声明一个类时,该类将自动拥有以下功能:
和枚举类型一样,记录也是类的一种受限形式。 作为回报,记录对象在简洁性方面提供了显著的好处。
但是需要注意:
这是 JDK 12 和 JDK 13 中的预览特性,现在是正式特性了。
我们使用 ->
来替代以前的 :
和 break
,另外还提供了 yield
来在 block 中返回值
代码演示:
public class SwitchExpression { public static void main(String[] args) { Season type = Season.AUTUMN; String s = switch (type) { case SPRING -> "春"; case SUMMER -> "夏"; case AUTUMN -> "秋"; case WINTER -> "冬"; default -> { System.out.println("没有" + type + "这个选项"); yield "error"; } }; } enum Season { SPRING, SUMMER, AUTUMN, WINTER } }
在 Java 中,通常需要使用 String 类型表达 HTML XML SQL 或 JSON 等格式的字符串,在进行字符串赋值时需要进行转义和连接操作,然后才能编译该代码,但这种表达方式难以阅读并且难以维护。
于是在 JDK13 中引入了 text blocks,JDK 14 进行了第二轮 preview,JDK14 的版本主要增加了两个功能,分别是 /
和 /s
例如我们要写一个 sql 语句,使用普通的字符串是这样的,这是比较简单的语句,如果复杂一点,简直不堪入目
@Test public void test1() { String sql = "SELECT name, age/n" + "FROM user/n" + "WHERE age = 19"; System.out.println(sql); }
使用了代码块是这样的,可读性变高了
@Test public void test2(){ String sql = """ SELECT name, age FROM user WHERE age = 19 """; System.out.println(sql); }
但是运行上述代码可以看出,代码块里写的是什么格式就会输出什么格式,如果我们想让它只输出一行,可读性也高呢?
这时,我们可以使用 JDK 14 新加的 /
(取消换行)和 /s
(一个空格)
@Test public void test3(){ String sql = """ SELECT name, age / FROM user/s/ WHERE age = 19/s/ """; System.out.println(sql); }
JDK 官方给出将这个 GC 组合标记为 Deprecate 的理由是:这个 GC 组合需要大量的代码维护工作,并且,这个 GC 组合很少被使用。因为它的使用场景应该是一个很大的 Young 区配合一个很小的 Old 区,这样的话, Old 区用 SerialOldGC 去收集时停顿时间我们才能勉强接受 。
废弃了 parallel young generation GC 与 SerialOld GC 的组合( XX:+UseParallelGC 与 XX: UseParallelOldGC 配合开启 ),现在使用 -XX:+UseParallelGC -XX:-UseParallelOldGC
或者 -XX:-UseParallelOldGC
都会出现如下警告:
Java HotSpot(TM) 64 Bit Server VM warning: Option UseParallelOldGC was deprecated in version 14.0 and will likely be removed in a future release.
该来的总会来,自从 G1 基于 Region 分代 )横空 出世后, CMS 在 JDK9 中就被标记为 Deprecate 了( JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector)
CMS 的弊端:
上述的这些问题,尤其是碎片化问题,给你的 JVM 实例就像埋了一颗炸弹。说不定哪次就在你的业务高峰期来一次 FGC。当 CMS 停止工作时,会把 Serial Old GC 作为备选方案,而 Serial Old GC 是 JVM 中性能最差的垃圾回收方式,停顿个几秒钟,上十秒都有可能 。
移除了 CMS 垃圾收集器,如果在 JDK14 中使用 XX:+UseConcMarkSweepGC
的话,JVM 不会报错,只是给出一个 warning 信息。
先看一下 ZGC 的恐怖性能,它可以在尽可能对吞吐量影响不大的前提下,实现在任意堆内存大小下都可以把垃圾收集的停顿时间限制在十毫秒以内的低延迟。
JDK14 之前, ZGC 仅 Linux 才支持 。尽管许多使用 ZGC 的用户都使用类 Linux 的环境,但在 Windows 和 macOS 上,人们也需要 ZGC 进行开发部署和测试。许多桌面应用也可以从 ZGC 中受益。因此, ZGC 特性被移植到了 Windows 和 macOS 上。
使用方式: -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
虽然 ZGC 还在试验状态,没有完成所有特性,但此时性能已经相当亮眼,用「令人震惊、革命性」来形容,不为过。未来将在服务端、大内存、低延迟应用的首选垃圾收集器。
有几个不重要的新特性没有列举,可自行查看相关资料
本文大部分的资料来源于此视频的课件: https://www.bilibili.com/video/BV1tC4y147US