亲宝软件园·资讯

展开

Java14:你需要知道的新特性

农夫三拳有点疼~ 人气:3

基本介绍

2020 年 3 月 17 日,JDK / Java 14 正式 GA(General Available)。这是自从 Java 采用六个月一次的发布周期之后的第五次发布。

此版本包含的 JEP Java/JDK Enhancement Proposals JDK 增强提案)比 Java 12 和 13 加起来的还要多。总共 16 个新特性,包括两个孵化器模块 、三 个预览特性、两个弃用的功能以及两个删除的功能。

  • 「孵化器模块」:将 尚未定稿的 API 和工具先交给开发者使用,以获得反馈,并用这些反馈进一步改进 Java 平台的质量。
  • 「预览特性」:是规格已经成型、实现已经确定,但还未最终定稿的功能。它们出现在 Java 中的目的是收集在真实世界中使用后的反馈信息,促进这些功能的最终定稿 。这些特性可能会随时改变,根据反馈结果, 这些特性甚至可能会被移除,但通常所有预览特性最后都会在 Java 中固定下来。

环境准备

安装 JDK 14 https://www.oracle.com/technetwork/java/javase/overview/index.html

安装编译器:IDEA 2020.1 或者 Eclipse 2020-03

新特性介绍

JEP 305:instanceof 的模式匹配(预览特性)

这个特性很有意思,因为它为更为通用的模式匹配打开了大门。模式匹配通过更为简便的语法基于一定的条件来抽取对象的组件,而 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 程序中显式强制转换的数量,从而提高生产力,还能实现更精确、简洁的类型安全的代码 。

JEP 358:非常实用的 NullPointerException

该特性改进了 NullPointerException 的可读性,能更准确地给出 null 变量的信息 。

就是这个老爷子当年发明的 null,让成千上万的程序员深恶痛绝,他称自己犯了一个价值十亿美金的错误,那就是空指针!

《Java 8 实战》中是这样说的:

  • 它是错误之源。 NullPointerException 是目前 Java 程序开发中最典型的异常。它会使你的代码膨胀。
  • 它让你的代码充斥着深度嵌套的 null 检查,代码的可读性糟糕透顶。
  • 它自身是毫无意义的。 null 自身没有任何的语义, 尤其是 它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。
  • 它破坏了 Java 的哲学。 Java 一直试图避免让程序员意识到指针的存在,唯一的例外是:null 指针。
  • 它在 Java 的类型系统上开了个口子。 null 并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题, 原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个 null 变量最初赋值到底是什么类型。

在 Java 8 中引入了 Optional,Optional 在可能为 null 的对象上做了一层封装,强制你思考值不存在的情况,这样
就能避免潜在的空指针异常 。

在 Java 14 中,对于 NPE 有了一个增强,该特性可以更好地提示哪个地方出现的空指针

需要我们在运行参数上加上 -XX:+ShowCodeDetailsInExceptionMessages 开启此功能,这个增强特性不仅适用于方法调用,只要会导致 NullPointerException 的地方也都适用,包括字段的访问、数组的访问和赋值 。

JEP 359:Record (预览特性)

我们有时候需要编写许多低价值的重复代码来实现一个简单的数据载体类:构造函数,访问器,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 声明一个类时,该类将自动拥有以下功能:

  • 获取成员变量的简单方法,以上面代码为例 name() 和 partner() 。注意区别于我们平常 getter 的写法。
  • 一个 equals 方法的实现,执行比较时会比较该类的所有成员属性
  • 重写 equals 当然要重写 hashCode
  • 一个可以打印该类所有成员属性的 toString 方法。
  • 请注意只会有一个构造方法。

和枚举类型一样,记录也是类的一种受限形式。 作为回报,记录对象在简洁性方面提供了显著的好处。

但是需要注意:

  • 可以在 Record 声明的类中定义静态字段、静态方法、构造器或实例方法。
  • 不能在 Record 声明的类中定义实例字段;类不能声明为 abstract;不能声明显式的父类等。

JEP 361:switch 表达式

这是 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
    }
}

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

在 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);
}

JEP 366 :弃用 ParallelScavenge 和 SerialOld GC 组合

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.

JEP 363 :删除 CMS 垃圾回收器

该来的总会来,自从 G1 基于 Region 分代 )横空 出世后, CMS 在 JDK9 中就被标记为 Deprecate 了( JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector)

CMS 的弊端:

  1. 会产生内存碎片,导致并发清除后,用户线程可用的空间不足 。
  2. 既然强调了并发( Concurrent),CMS 收集器 对 CPU 资源非常敏感。
  3. CMS 收集器无法处理浮动垃圾

上述的这些问题,尤其是碎片化问题,给你的 JVM 实例就像埋了一颗炸弹。说不定哪次就在你的业务高峰期来一次 FGC。当 CMS 停止工作时,会把 Serial Old GC 作为备选方案,而 Serial Old GC 是 JVM 中性能最差的垃圾回收方式,停顿个几秒钟,上十秒都有可能 。

移除了 CMS 垃圾收集器,如果在 JDK14 中使用 XX:+UseConcMarkSweepGC 的话,JVM 不会报错,只是给出一个 warning 信息。

JEP:ZGC on macOS and windows

先看一下 ZGC 的恐怖性能,它可以在尽可能对吞吐量影响不大的前提下,实现在任意堆内存大小下都可以把垃圾收集的停顿时间限制在十毫秒以内的低延迟。

JEP 364:ZGC 应用在 macOS 上、JEP 365:ZGC 应用在 Windows 上

JDK14 之前, ZGC 仅 Linux 才支持 。尽管许多使用 ZGC 的用户都使用类 Linux 的环境,但在 Windows 和 macOS 上,人们也需要 ZGC 进行开发部署和测试。许多桌面应用也可以从 ZGC 中受益。因此, ZGC 特性被移植到了 Windows 和 macOS 上。

使用方式:-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

虽然 ZGC 还在试验状态,没有完成所有特性,但此时性能已经相当亮眼,用「令人震惊、革命性」来形容,不为过。未来将在服务端、大内存、低延迟应用的首选垃圾收集器。


有几个不重要的新特性没有列举,可自行查看相关资料

本文大部分的资料来源于此视频的课件:https://www.bilibili.com/video/BV1tC4y147US

加载全部内容

相关教程
猜你喜欢
用户评论