JDK14你必须了解的新特性

Pattern Matching for instanceof (Preview) (instanceof的模式匹配预览版)

JDK14之前的写法

Object obj = "kuaidi100";
if(obj instanceof String){
    String str = (String) obj;
}

JDK14后可以这样写

Object obj = "kuaidi100";
if(obj instanceof String str){
    //直接使用str
}
if (obj instanceof String s) {
    // can use s here
} else {
    // can't use s here
}

Switch Expressions (Switch表达式)

经过JDK12,13的迭代,最后在JDK14中将这个特性转正。

T result = switch (arg) {
    case L1 -> e1;
    case L2 -> e2;
    default -> e3;
};
int result = switch (s) {
    case "Foo": 
        yield 1;
    case "Bar":
        yield 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        yield 0;
};

JFR Event Streaming JFR事件流

这个特性是JDK11 飞行记录器的升级功能,在JDK11中JFR只能将运行的数据导出文件,然后通过JMC可视化,这个过程太繁琐也不能应用于实时的监控,所以在JDK14中推出了JFR事件流。通过这个功能可以实时获取到JVM的运行情况。


Non-Volatile Mapped Byte Buffers 非易失性映射的字节缓冲

新的特定于jdk的文件映射模式,以便可以使用FileChannel API创建引用非易失性内存的MappedByteBuffer实例。在non-vllatile的情况下,如果像RAM一样关闭电源,数据也不会保留。唯一需要更改的API是FileChannel客户端使用的新枚举,用于请求位于NVM支持的文件系统(而不是传统的文件存储系统)上的文件的映射。


Helpful NullPointerExceptions 有用的NPE

在之前抛出NPE异常时只会提示哪一行出错了,但是那一行有多个操作,无法分辨出那个是null。比如下面的例子,不知道是a,还是b,还是c是null。

a.b.c.i = 99;

在JDK14前只是会提示哪一行有错误。

Exception in thread "main" java.lang.NullPointerException
    at Prog.main(Prog.java:5)

在JDK14中就会明确的提示是那个字段为空。

Exception in thread "main" java.lang.NullPointerException: 
        Cannot assign field "i" because "a" is null
    at Prog.main(Prog.java:5)

不过这个功能默认是关闭的,需要使用-XX:+ShowCodeDetailsInExceptionMessages来开启。之所以不默认打开是出于性能,安全,兼容性三个方面的考虑。


Records (Preview)记录类型预览版

Java的语法太过繁琐一直被吐槽,想要创建纯数据载体类通常都必须编写大量低价值、重复的、容易出错的代码。如:构造函数、getter/setter、equals()、hashCode()以及toString()等。很多人会选择使用IDE或者Lombok来生成这些代码,但是使用这些工具有时会有意想不到的结果,甚至引发生产BUG。所以在JDK14推出了一个纯数据载体的类型——record。

下面是一个record例子:

public record Kuaidi100Record(@Name("name") int x, int y) {
    public static String one;
}

生成的class文件反编译后:

public record Kuaidi100Record(int x, int y) {
    public static String one;

    public Kuaidi100Record(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Name("name")
    public int x() {
        return this.x;
    }

    public int y() {
        return this.y;
    }
}

javap查看对应的汇编指令:

public final class feature_record.Kuaidi100Record extends java.lang.Record {
  public static java.lang.String one;

  public feature_record.Kuaidi100Record(int, int);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Record."<init>":()V
       4: aload_0
       5: iload_1
       6: putfield      #7                  // Field x:I
       9: aload_0
      10: iload_2
      11: putfield      #13                 // Field y:I
      14: return

  public final java.lang.String toString();
    Code:
       0: aload_0
       1: invokedynamic #16,  0             // InvokeDynamic #0:toString:(Lfeature_record/Kuaidi100Record;)Ljava/lang/String;
       6: areturn

  public final int hashCode();
    Code:
       0: aload_0
       1: invokedynamic #20,  0             // InvokeDynamic #0:hashCode:(Lfeature_record/Kuaidi100Record;)I
       6: ireturn

  public final boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokedynamic #24,  0             // InvokeDynamic #0:equals:(Lfeature_record/Kuaidi100Record;Ljava/lang/Object;)Z
       7: ireturn

  public int x();
    Code:
       0: aload_0
       1: getfield      #7                  // Field x:I
       4: ireturn

  public int y();
    Code:
       0: aload_0
       1: getfield      #13                 // Field y:I
       4: ireturn
}

使用

public static void main(String[] args) {
        Kuaidi100Record kuaidi100Record = new Kuaidi100Record(1, 2);
        System.out.println(kuaidi100Record);
}

通过上面的class文件与javap生成的汇编代码可以看到record做了下面几件事情:

  1. 没有指定构造器,Record 类会自动生成一个以所有属性为参数并且给每个属性赋值的构造器
  2. 生成成员变量的get方法,没有set方法。

get方法生成规则:

      • 方法名就是属性名称
      • 返回类型就是对应的属性类型
      • 是一个 public 方法,并且没有声明抛出任何异常
      • 方法体就是返回对应属性
      • 如果属性上面有任何注解,那么这个注解如果能加到方法上那么也会自动加到这个方法上

3. 重写equals,hashCode,toString等方法。

      • hashcode() 在编译的时候自动生成字节码实现,核心逻辑基于 ObjectMethods 的 makeHashCode 方法,里面的逻辑是对于每一个属性的哈希值移位组合起来。注意这里的所有调用(包括对于 ObjectMethods 的方法调用以及获取每个属性)都是利用 MethodHandle 实现的近似于直接调用的方式调用的。
      • equals() 在编译的时候自动生成字节码实现,核心逻辑基于 ObjectMethods 的 makeEquals 方法,里面的逻辑是对于两个 Record 对象每一个属性判断是否相等(对于引用类型用Objects.equals(),原始类型使用 ==),注意这里的所有调用(包括对于 ObjectMethods 的方法调用以及获取每个属性)都是利用 MethodHandle 实现的近似于直接调用的方式调用的。
      • toString() 在编译的时候自动生成字节码实现,核心逻辑基于 ObjectMethods 的 makeToString 方法,里面的逻辑是对于每一个属性的值组合起来构成字符串。注意这里的所有调用(包括对于 ObjectMethods 的方法调用以及获取每个属性)都是利用 MethodHandle 实现的近似于直接调用的方式调用的。

4.record默认为final的,成员变量也为final,所以没有set方法。

record特性在JDK14还只是预览版,在JDK15中对它进行了继续加强。


Foreign-Memory Access API (Incubator)外部存储器访问特性孵化

引入API以允许Java程序安全有效地访问Java堆之外的外部存储器。实现了一种提供“通用性”,“安全性”和“确定性”的“外部存储器API,用来替换 java.nio.ByteBuffer和sun.misc.Unsafe。

JDK引入这个特性的动机是现在有许多基于Java的库和应用都使用了堆外内存访问,比如mapDB,netty的ByteBuf,memcached等。使用堆外内存的动机:

  • 避免GC不可预测和性能损耗
  • 多个进程之间共享内存
  • 通过将文件映射到内存中(例如,通过mmap)来序列化和反序列化内存内容

但是在JDK14之前JDK并没有提供很好的堆外内存访问的API

在1.4引进的ButeBuffer允许创建direct类型的byte来进行堆外内存操作,但是它处理的内存不能超过2G。只有当垃圾收集器认为直接缓冲区不可达时,关联的内存才会被释放。此外,使用直接缓冲区可能很麻烦,因为与直接缓冲区关联的内存的回收工作留给了垃圾收集器。除了ByteBuffer外还可以使用Unsafe来进行堆外内存访问,但是由于它允许访问任何内存位置(例如,不安全::gettint需要一个长地址)。这使得Java程序有可能使JVM崩溃。

为此在JDK14引入了MemorySegment, MemoryAddress and MemoryLayout。


其他特性

移除CMS垃圾收集器

ZGC支持windows,macOS

弃用ParallelScavenge + SerialOld GC组合

Text Blocks (Second Preview):这个在JDK13中推出,在JDK14中继续对其进行了扩展。

Packaging Tool (Incubator):一个打包工具,可以将java应用直接打包成rpm,dmg或者exe在各自平台可以点击直接运行。

NUMA-Aware Memory Allocation for G1:通过实现NUMA-ware(非统一内存访问)内存分配提升G1在大型机的性能。


完整特性

305:Pattern Matching for instanceof (Preview)
343:Packaging Tool (Incubator)
345:NUMA-Aware Memory Allocation for G1
349:JFR Event Streaming
352:Non-Volatile Mapped Byte Buffers
358:Helpful NullPointerExceptions
359:Records (Preview)
361:Switch Expressions (Standard)
362:Deprecate the Solaris and SPARC Ports
363:Remove the Concurrent Mark Sweep (CMS) Garbage Collector
364:ZGC on macOS
365:ZGC on Windows
366:Deprecate the ParallelScavenge + SerialOld GC Combination
367:Remove the Pack200 Tools and API
368:Text Blocks (Second Preview)
370:Foreign-Memory Access API (Incubator)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值