Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
323 lines (225 loc) · 12.5 KB

File metadata and controls

323 lines (225 loc) · 12.5 KB
Copy raw file
Download raw file
Outline
Edit and raw actions
title Java 14 & 15 新特性概览
description 概览 JDK 14/15 的关键特性,如 record、文本块与空指针精准提示等语言增强。
category Java
tag
Java新特性
head
meta
name content
keywords
Java 14,Java 15,record,文本块,NullPointerException 细节,模式匹配,JEP

Java 14

JDK 14 于 2020 年 3 月 17 日发布,这是一个非 LTS 版本。

这篇文章会挑选其中较为重要的一些新特性进行详细介绍:

下图是从 JDK 8 到 JDK 25 每个版本的更新带来的新特性数量和更新时间:

 JDK 8 到 JDK 25 每个版本的更新带来的新特性数量和更新时间

JEP 305: Pattern Matching for instanceof(instanceof 模式匹配,预览)

Java 14 继续将 instanceof 模式匹配作为预览特性,这是 Java 14 引入的功能(JEP 305)。

该特性允许在 instanceof 检查的同时进行类型转换,避免了显式强制转换的需要。注意:instanceof 模式匹配在 Java 14 是第一次预览(JEP 305),在 Java 15 是第二次预览(JEP 375),最终在 Java 16 转正(JEP 394)。

JEP 358: Helpful NullPointerExceptions(空指针异常精准提示)

通过 JVM 参数中添加-XX:+ShowCodeDetailsInExceptionMessages,可以在空指针异常中获取更为详细的调用信息,更快的定位和解决问题。

a.b.c.i = 99; // 假设这段代码会发生空指针

Java 14 之前:

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

Java 14 之后:

 // 增加参数后提示的异常中很明确的告知了哪里为空导致
Exception in thread "main" java.lang.NullPointerException:
        Cannot read field 'c' because 'a.b' is null.
    at Prog.main(Prog.java:5)

JEP 361: Switch Expressions(switch 表达式,标准版)

Java 12 引入的 switch(预览特性)在 Java 14 变为正式版本,不需要增加参数来启用,直接在 JDK 14 中就能使用。

Java 12 为 switch 表达式引入了类似 lambda 语法条件匹配成功后的执行块,不需要多写 break,Java 13 提供了 yield 来在 block 中返回值。

String result = switch (day) {
            case "M", "W", "F" -> "MWF";
            case "T", "TH", "S" -> "TTS";
            default -> {
                if(day.isEmpty())
                    yield "Please insert a valid day.";
                else
                    yield "Looks like a Sunday.";
            }

        };
System.out.println(result);

JEP 359: Records(record 类,预览)

record 关键字可以简化 数据类(一个 Java 类一旦实例化就不能再修改)的定义方式,使用 record 代替 class 定义的类,只需要声明属性,就可以在获得属性的访问方法,以及 toString()hashCode(), equals()方法。

类似于使用 class 定义类,同时使用了 lombok 插件,并打上了@Getter,@ToString,@EqualsAndHashCode注解。

/**
 * 这个类具有两个特征
 * 1. 所有成员属性都是final
 * 2. 全部方法由构造方法,和两个成员属性访问器组成(共三个)
 * 那么这种类就很适合使用record来声明
 */
final class Rectangle implements Shape {
    final double length;
    final double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    double length() { return length; }
    double width() { return width; }
}
/**
 * 1. 使用 record 声明的类会自动拥有上面类中的三个方法
 * 2. 在这基础上还附赠了 equals(),hashCode() 方法以及 toString() 方法
 * 3. toString 方法中包括所有成员属性的字符串表示形式及其名称
 */
record Rectangle(float length, float width) { }

JEP 368: Text Blocks(文本块,第二次预览)

Java14 中,文本块依然是预览特性,不过,其引入了两个新的转义字符:

  • \ : 表示行尾,不引入换行符
  • \s:表示单个空格
String str = "凡心所向,素履所往,生如逆旅,一苇以航。";

String str2 = """
        凡心所向,素履所往, \
        生如逆旅,一苇以航。""";
System.out.println(str2);// 凡心所向,素履所往, 生如逆旅,一苇以航。
String text = """
        java
        c++\sphp
        """;
System.out.println(text);
//输出:
java
c++ php

其他特性

  • 从 Java11 引入的 ZGC 作为继 G1 过后的下一代 GC 算法,从支持 Linux 平台到 Java14 开始支持 MacOS 和 Windows(个人感觉是终于可以在日常开发工具中先体验下 ZGC 的效果了,虽然其实 G1 也够用)
  • JEP 363: Remove the CMS Garbage Collector (移除 CMS 垃圾收集器,功成而退)
  • 新增了 jpackage 工具,标配将应用打成 jar 包外,还支持不同平台的特性包,比如 linux 下的debrpm,window 平台下的msiexe

Java 15

JDK 15 于 2020 年 9 月 15 日发布,这是一个非 LTS 版本。

这篇文章会挑选其中较为重要的一些新特性进行详细介绍:

下图是从 JDK 8 到 JDK 24 每个版本的更新带来新特性数量和更新时间:

JEP 379: Shenandoah(Shenandoah GC,标准版)

Shenandoah 垃圾收集器从 Java 12 开始作为实验性特性引入,经过多个版本的迭代和完善,在 Java 15 终于转正为正式特性。

Shenandoah 是 Red Hat 主导开发的低延迟垃圾收集器,主要目标是:

  • 99.9% 的 GC 停顿时间小于 10ms
  • 停顿时间与堆大小无关
  • 支持从几百 MB 到几 TB 的堆内存

与 G1 和 ZGC 不同,Shenandoah 采用并发标记-整理算法,可以在不停止应用线程的情况下进行垃圾回收。

启用 Shenandoah GC:

java -XX:+UseShenandoahGC className

JEP 339: EdDSA(数字签名算法)

新加入了一个安全性和性能都更强的基于 Edwards-Curve Digital Signature Algorithm (EdDSA)实现的数字签名算法。

虽然其性能优于现有的 ECDSA 实现,不过,它并不会完全取代 JDK 中现有的椭圆曲线数字签名算法( ECDSA)。

KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();

byte[] msg = "test_string".getBytes(StandardCharsets.UTF_8);

Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();

String encodedString = Base64.getEncoder().encodeToString(s);
System.out.println(encodedString);

输出:

0Hc0lxxASZNvS52WsvnncJOH/mlFhnA8Tc6D/k5DtAX5BSsNVjtPF4R4+yMWXVjrvB2mxVXmChIbki6goFBgAg==

JEP 378: Text Blocks(文本块,标准版)

在 Java 15,文本块终于转正为正式功能特性,不再需要 --enable-preview 参数即可使用。

文本块提供了一种更简洁的方式来定义多行字符串,特别适合用于 SQL、JSON、HTML 等场景。

JEP 371: Hidden Classes(隐藏类)

隐藏类是为框架(frameworks)所设计的,支持动态生成的类,这些类不能直接被其他类的字节码使用,只能在运行时通过反射间接使用它们。

主要特点:

  • 不可被发现:隐藏类不能被其他类直接依赖
  • 生命周期短:通常在使用完毕后就会被卸载
  • 性能优化:为动态语言运行时提供了更好的性能支持

适用场景:

  • 动态语言运行时(如 JavaScript、Groovy)
  • 字节码生成框架(如 ASM、CGLIB)
  • 反射代理(如动态代理)

JEP 360: Sealed Classes(密封类,预览)

密封类(Sealed Classes) 是 Java 15 中的一个预览新特性。

没有密封类之前,在 Java 中如果想让一个类不能被继承和修改,我们可以使用final 关键字对类进行修饰。不过,这种方式不太灵活,直接把一个类的继承和修改渠道给堵死了。

密封类可以对继承或者实现它们的类进行限制,这样这个类就只能被指定的类继承。

// 抽象类 Person 只允许 Employee 和 Manager 继承。
public abstract sealed class Person
    permits Employee, Manager {

    //...
}

另外,任何扩展密封类的类本身都必须声明为 sealednon-sealedfinal

public final class Employee extends Person {
}

public non-sealed class Manager extends Person {
}

如果允许扩展的子类和封闭类在同一个源代码文件里,封闭类可以不使用 permits 语句,Java 编译器将检索源文件,在编译期为封闭类添加上许可的子类。

JEP 375: Pattern Matching for instanceof(instanceof 模式匹配,第二次预览)

Java 15 继续将 instanceof 模式匹配作为预览特性,没有进行重大调整,主要是为了收集更多使用反馈。

instanceof 模式匹配允许在类型检查的同时进行变量绑定,避免了显式类型转换,使代码更简洁安全。

示例:

// 传统写法
if (obj instanceof String) {
    String str = (String) obj;
    System.out.println(str.length());
}

// 模式匹配写法
if (obj instanceof String str) {
    System.out.println(str.length());
}

API 增强

CharSequence 增强

在 Java 15 之前,如果你想判断一个 StringBuilderStringBuffer 或者 CharBuffer 是否为空,通常需要调用 length() == 0

CharSequence 接口添加了一个默认方法 isEmpty() 来判断字符序列为空,如果是则返回 true。

public interface CharSequence {
  default boolean isEmpty() {
      return this.length() == 0;
  }
}

由于 StringStringBuilder 等都实现了这个接口,现在你可以用更统一、更具语义化的方式来编写判断逻辑。这对于编写泛型代码(处理各种字符序列)非常友好。

注意: String 类虽然早已有了 isEmpty() 方法,但那个是 String 自己定义的;Java 15 这一步是将该能力“上浮”到了接口层。

TreeMap 性能提升

这是一个非常硬核的优化。虽然 putIfAbsent()compute() 等方法早在 Java 8 就出现在 Map 接口中了,但在 Java 15 之前,TreeMap 并没有自己去实现它们,而是直接沿用接口里的 default 实现。

Java 15 的变化TreeMap 专门重写了以下方法:

  • putIfAbsent()
  • computeIfAbsent()
  • computeIfPresent()
  • compute()
  • merge()

为什么要重写?

  • 性能提升:接口里的默认实现通常比较“笨”,往往需要进行多次查找(例如先查找是否存在,再决定是否插入)。
  • O(log n) 保证TreeMap 优化后的实现可以将查找和插入合并在一次红黑树遍历中完成,避免了重复的树搜索,显著提升了在处理大规模数据时的执行效率。

其他特性

  • Nashorn JavaScript 引擎彻底移除:Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性。在 Java 11 中就已经被弃用,到了 Java 15 就彻底被删除了。
  • DatagramSocket API 重构
  • 禁用和废弃偏向锁(Biased Locking):偏向锁的引入增加了 JVM 的复杂性大于其带来的性能提升。不过,你仍然可以使用 -XX:+UseBiasedLocking 启用偏向锁定,但它会提示这是一个已弃用的 API。
  • ……
Morty Proxy This is a proxified and sanitized view of the page, visit original site.