Bootstrap

java15特性介绍

0.译者按

本文翻译自What’s New in Java 15

1.介绍

java15已于2020年九月发版,是一个短期jdk版本。在早期发行版本的一些特性基础上做了加强。本文涉及java15的新特性和一些java开发者刚兴趣的变化。

2.Records (JEP 384)

record是java的一个class type(译者:是的,在class之上又抽了一层type,已知具体类型有record,sealed[后面会介绍到]等)。主要用于简化只读数据对象【immutable data object】的创建。该特性在java14已经以“preview”的形式被提出,并于本版本被强化,但还不算做正式版本特性。

2.1 record之前

先来看一下没有record特性时我们定义一个只读对象:

public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

不难发现,为了定义一个只读对象,我们写了很多的代码:

  • 明确声明成员变量为final
  • 有且只有一个包含全变成员变量的构造器
  • 对每个成员变量只有getter方法,而没有setter方法
  • 我们甚至可以把该类声明成final,以免该类被继承
  • 还有toString方法、equals方法、hashCode方法我们都还没有写出,一旦写出,那么该类的代码量将翻遍。

2.2 record现身

看我们可使用record来以一种更加紧凑简化的方式来定义只读类:

public record Person(String name, int age) {}

请注意,和以往的类定义方式不同,这里用到了一个新的语法:用关键字record来指定具体的class type。那么这个语法的实际意义是什么呢?很简单,就是为我们自动生成了在2.1节中我们手动编写的代码。生成时机,自然是编译期了,因为我们在写代码要用到这些方法的。这些方法可见下面的反编译代码:

// Compiled from "ExampleRecord.java"
// 请忽略它是内部类这一点
public final class best.pratice.jdk15.ExampleRecord$Person extends java.lang.Record {
  public best.pratice.jdk15.ExampleRecord$Person(java.lang.String, int);
  public final java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public java.lang.String name();
  public int age();
}

可见,record为我们省掉了太多的代码了。然而,它确实有一些局限:

  1. 它们是final类型(反编译源码可见)
  2. 它们不能被声明为abstract
  3. 不能使用native方法(这一点对一般开发者没有影响)

3.Sealed Classes (JEP 360)

sealed class的目的是允许类或者接口,声明它可以被哪些子类型实现。是一种对类层次的深度的限制。

sealed class涉及到两个关键字:sealed 和 permits (瞅瞅这关键字的时态和词形)

public abstract sealed class Person
    permits Employee, Manager {
 
    //...
}

        这里我们声明了一个抽象类Person,并且指明了只有Employee和Manager类才能集成该抽象类。继承抽象类的语法和现行语法相同,但是有个限制:子类必须是final或者sealed或者non-sealed(non-sealed难倒不是第三个关键字吗),这样的机制就把类继承机制的无限继承限制在了有限层级范围。编译器完全能感知到这种继承限制,并能对我们的编码做一定的优化(其实是限制,有益的限制),它允许我们如下编码:

if (person instanceof Employee) {
    return ((Employee) person).getEmployeeId();
} 
else if (person instanceof Manager) {
    return ((Manager) person).getSupervisorId();
}
// 这里不用再用else来兜底,编译器也不会报编译错误,因为编译器知道这里if...else if已经把可能的分支完全覆盖了。

4.Hidden Classes (JEP 371)

        hidden class是java15版本发布的一个新特性。虽然大部分java开发者不会直接从中受益,但对于工作内容是动态字节码和jvm语言的底层开发工程师来讲确为一则喜讯。

顾名思义,hidden clas的目标就是允许运行时创建一些不易被察觉到的类。这些隐藏类不能被编译时linked(因为编译器它们还没有生成),也不能被java的反射机制发现。它们的生命周期很短,因此他们的设计意图是为了高效的加载类和卸载类(这一句对于那些字节码层次的开发人员很有诱惑力吧)。诚然,现行java支持创建的匿名类是和隐藏类是有几分相似的,但是前者是依赖UnsafeAPI,而后者则无依赖。

5.Pattern Matching Type Checks (JEP 375)

        模式匹配类型检查特性早在java14时就以“preview”预览状态出现了,而java15继续保持该状态,并且没有对此做任何增强。该特性主要用来消除样板代码,比如在instanceof操作符

// 往常的代码:instanceof判断之后,紧跟着就是一个类型强转。
if (person instanceof Employee) {
    Employee employee = (Employee) person;
    Date hireDate = employee.getHireDate();
    //...
}

// ‘模式匹配特性’帮我们把instanceof判断和类型强转合二为一。
if (person instanceof Employee employee) {
    Date hireDate = employee.getHireDate();
    //...
}

// ‘模式匹配特性’甚至允许我们继续对强转后的变量做逻辑判断
if (person instanceof Employee employee && employee.getYearsOfService() > 5) {
    //...
}

未来‘模式匹配特性’还会用于switch语句中。

6. Foreign Memory API (JEP 383)

        “外部内存访问”特性在java14中是“incubating”孕育状态,在java15中依然如是,只不过后者给它增加了几个新功能点:

  • 一个全新的VarHandle APi,用于通过handles的方式来定制化内存访问
  • 通过 Spliterator 接口,支持读内存分片的并行化处理
  • 加强对 mapped 内存分片的支持
  • 在native方法调用时支持对内存地址的操作和反向引用

        外部内存一般指非jvm堆内内存,当然它也不归java的垃圾收集机制管,而且它经常能操作巨大的内存分片。

        以上新的api不会直接给大部分的程序员带来福音,但是却能给需要管理外部内存的第三方类库开发者送去实惠,比如分布式缓存、非规范文档存储、任意大的字节缓冲、内存映射文件等等。

7.Garbage Collectors

        在java15中,ZGC (JEP 377) 和Shenandoah (JEP 379) 都已经完成试验阶段,它们都可以通过配置的形式来选择使用。有必要说明一点,先前的G1收集器依然是默认的垃圾收集器。关于Shenandoah有一点需要注意:并不是所有供应商的JDK都可以使用它,尤其是Oracle JDK没有包含它。

8.Other Changes

java15中还有其他几个值得留意的改变:

  1. 经过了两轮‘预览’版本之后,文本块(text blocks)已经在java15中得到了完全的支持。
  2. 有用NPE特性,最早在java14中推出,可使用jvm参数开启;在java15中该配置已是默认开启
  1. Java 15包括对Edwards-Curve数字签名算法的加密支持。EdDSA是一种新型的椭圆曲线签名方案,与JDK中现有的签名方案相比,EdDSA具有许多优点。
  2. Biased locking、 Solaris/SPARC ports、RMI Activatio 在java15中已经废弃或者计划废弃

9总结

        在已发布的版本的基础上,java15提供了records、text blocks、新垃圾收集算法。它也新增了几个“preview”状态的特性:sealed classes、hidden classes。

        java15不是一个长期版本,最多到2021年三月,届时讲推出java16,同样是一个短期版本。最近的一个长期版本是java17。

;