JDK21新特性Record Patterns记录模式详解

这篇具有很好参考价值的文章主要介绍了JDK21新特性Record Patterns记录模式详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 摘要

通过使用记录模式来增强Java编程语言,以解构记录值。记录模式和类型模式可嵌套使用,从而实现强大、声明式和可组合的数据导航和处理形式。

2 发展史

由 JEP 405 提出的预览功能,并在JDK 19发布,然后由 JEP 432 再次预览,并在JDK 20发布。该功能与用于switch的模式匹配(JEP 441)共同演进,并且二者有相当大的交互作用。本JEP提议在持续的经验和反馈基础上对该功能完善。

除了一些次要的编辑更改,自第二个预览版以来的主要变化是删除了对增强for语句头部出现记录模式的支持。这个功能可能会在未来的JEP中重提。

3 目标

  • 扩展模式匹配以解构记录类的实例,实现更复杂的数据查询
  • 添加嵌套模式,实现更可组合的数据查询

4 动机

Java 16中, JEP 394 扩展了instanceof运算符,使其可接受类型模式并执行模式匹配。这个简单的扩展使得熟悉的instanceof和强制转换惯用法变得更简洁、更不易出错:

// <Java 16
if (obj instanceof String) {
    String s = (String)obj;
    ... 使用s ...
}
// ≥Java 16
if (obj instanceof String s) {
    ... 使用s ...
}

新代码中,若obj在运行时是String的实例,则obj与类型模式String s匹配。若模式匹配成功,则instanceof true,且模式变量s被初始化为obj强制转换为String的值,然后可以在包含的代码块中使用。

类型模式一次性消除了许多类型转换的出现。然而,它们只是朝着更声明式、以数据为焦点的编程风格迈出的第一步。随Java支持新的、更具表现力的数据建模,模式匹配可通过让开发表达模型的语义意图来简化对这些数据的使用。

5 Pattern matching和records

记录 (JEP 395) 是数据的透明载体。接收记录类实例的代码通常会使用内置的组件访问器方法提取数据,即组件。

5.1 Point的实例

如用类型模式测试一个值是否是记录类Point的实例,并在匹配成功时从该值中提取x和y组件。

Java8

class Point {
    private int x;
    private int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public int getX() {
        return x;
    }
    
    public int getY() {
        return y;
    }
}

static void printSum(Object obj) {
    if (obj instanceof Point) {
        Point p = (Point) obj;
        int x = p.getX();
        int y = p.getY();
        System.out.println(x + y);
    }
}

≥Java 16

record Point(int x, int y) {}

static void printSum(Object obj) {
    if (obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}

仅使用模式变量p调用访问方法x()、y(),这些方法返回组件x和y的值。

在每个记录类中,其访问方法和组件之间存在一对一对应关系。

如果模式不仅可测试一个值是否是Point的实例,还可直接从该值中提取x和y组件,从而代表我们调用访问器方法的意图将更好。换句话说:

// Java 21及以后
static void printSum(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

Point(int x, int y) 是一个record pattern。它将用于提取组件的局部变量的声明直接提升到模式本身,并在值与模式匹配时通过调用访问方法对这些变量初始化。实际上,record pattern将记录的实例解构为其组件。

6 嵌套record pattern

模式匹配的真正威力在于优雅扩展到匹配更复杂的对象图。

考虑以下声明:

// Java 16及以后
record Point(int x, int y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}

已知可使用记录模式提取对象的组件。如想从左上角点提取颜色:

// Java 21及以后
static void printUpperLeftColoredPoint(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint ul, ColoredPoint lr)) {
         System.out.println(ul.c());
    }
}

但ColoredPoint值ul本身是个记录值,希望进一步分解。因此,记录模式支持嵌套,允许对记录组件进一步匹配、分解。可在记录模式中嵌套另一个模式,同时对外部和内部记录分解:

// Java 21及以后
static void printColorOfUpperLeftPoint(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point p, Color c),
                               ColoredPoint lr)) {
        System.out.println(c);
    }
}

嵌套模式允许以与组装对象的代码一样清晰简洁方式拆解聚合。如创建一个矩形,通常会将构造函数嵌套在一个表达式中:

// Java 16及以后
Rectangle r = new Rectangle(new ColoredPoint(new Point(x1, y1), c1), 
                            new ColoredPoint(new Point(x2, y2), c2));

使用嵌套模式,我们可以使用与嵌套构造函数结构相似的代码来解构这样的矩形:

// Java 21及以后
static void printXCoordOfUpperLeftPointWithPatterns(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point(var x, var y), var c),
                               var lr)) {
        System.out.println("Upper-left corner: " + x);
    }
}

嵌套模式可能无法匹配:

// Java 21及以后
record Pair(Object x, Object y) {}
Pair p = new Pair(42, 42);
if (p instanceof Pair(String s, String t)) {
    System.out.println(s + ", " + t);
} else {
    System.out.println("Not a pair of strings");
}

这里的记录模式Pair(String s, String t)包含了两个嵌套的类型模式,即String s和String t。如果一个值与模式Pair(String s, String t)匹配,那么它是一个Pair,并且递归地,它的组件值与类型模式String s和String t匹配。在我们上面的示例代码中,由于记录的两个组件值都不是字符串,因此这些递归的模式匹配失败,因此执行else块。

总之,嵌套模式消除了导航对象的意外复杂性,使我们能专注这些对象所表示的数据。它们还赋予我们集中处理错误的能力,因为如果一个值无法与嵌套模式P(Q)匹配,那子模式P和Q中的任何一个或两个都无法匹配。我们不需要检查和处理每个单独的子模式匹配失败——要么整个模式匹配,要么不匹配。

7 描述

使用可嵌套的记录模式。

模式语法变为:

Pattern:
  TypePattern
  RecordPattern

TypePattern:
  LocalVariableDeclaration

RecordPattern:
  ReferenceType ( [ PatternList ] )

PatternList: 
  Pattern { , Pattern }

8 记录模式

由记录类类型和(可能为空的)模式列表组成,该列表用于与相应的记录组件值进行匹配。

如声明

record Point(int i, int j) {}

如果值v与记录模式Point(int i, int j)匹配,则它是记录类型Point的实例;如这样,模式变量i将被初始化为在值v上调用与i对应的访问器方法的结果,模式变量j将被初始化为在值v上调用与j对应的访问器方法的结果。(模式变量的名称不需要与记录组件的名称相同;也就是说,记录模式Point(int x, int y)的行为相同,只是模式变量x和y被初始化。)

null值不与任何记录模式匹配。

记录模式可用var来匹配记录组件,而无需声明组件的类型。在这种情况下,编译器会推断由var模式引入的模式变量的类型。如模式Point(var a, var b)是模式Point(int a, int b)的简写。

记录模式声明的模式变量集合包括模式列表中声明的所有模式变量。

如果一个表达式可以在不需要未经检查的转换的情况下将其转换为模式中的记录类型,则该表达式与记录模式兼容。

如果记录模式命名了一个泛型记录类,但没有给出类型参数(即,记录模式使用原始类型),则始终会推断类型参数。例如:

// Java 21及以后
record MyPair<S,T>(S fst, T snd){};
static void recordInference(MyPair<String, Integer> pair){
    switch (pair) {
        case MyPair(var f, var s) -> 
            ... // 推断的记录模式 MyPair<String,Integer>(var f, var s)
        ...
    }
}

记录模式的类型参数推断在支持记录模式的所有结构中都受到支持,即instanceof表达式和switch语句和表达式。

推断适用于嵌套记录模式;例如:

// Java 21及以后
record Box<T>(T t) {}
static void test1(Box<Box<String>> bbs) {
    if (bbs instanceof Box<Box<String>>(Box(var s))) {
        System.out.println("String " + s);
    }
}

这里,嵌套模式Box(var s)的类型参数被推断为String,因此模式本身被推断为Box(var s)。

甚至可省略外部记录模式中的类型参数,得到简洁代码:

// Java 21及以后
static void test2(Box<Box<String>> bbs) {
    if (bbs instanceof Box(Box(var s))) {
        System.out.println("String " + s);
    }
}

这里编译器会推断整个instanceof模式为Box<Box<String>>(Box<String>(var s))

为保持兼容性,类型模式不支持隐式推断类型参数;如类型模式List l始终被视为原始类型模式。

9 记录模式和完整的switch

JEP 441增强了switch表达式和switch语句,以支持模式标签。无论是switch表达式还是模式switch语句,都必须是完整的:switch块必须有处理选择器表达式的所有可能值的子句。对于模式标签,这是通过分析模式的类型来确定的;例如,case标签case Bar b匹配类型为Bar及其所有可能的子类型的值。

对于涉及记录模式的模式标签,分析更加复杂,因为我们必须考虑组件模式的类型,并对密封层次结构进行调整。例如,考虑以下声明:

class A {}
class B extends A {}
sealed interface I permits C, D {}
final class C implements I {}
final class D implements I {}
record Pair<T>(T x, T y) {}
Pair<A> p1;
Pair<I> p2;

以下switch不是完整的,因为没有匹配包含两个类型为A的值的对:

// Java 21及以后
switch (p1) {                 // 错误!
    case Pair<A>(A a, B b) -> ...
    case Pair<A>(B b, A a) -> ...
}

这两个switch是完整的,因为接口I是密封的,因此类型C和D涵盖了所有可能的实例:

// Java 21及以后
switch (p2) {
    case Pair<I>(I i, C c) -> ...
    case Pair<I>(I i, D d) -> ...
}

switch (p2) {
    case Pair<I>(C c, I i) -> ...
    case Pair<I>(D d, C c) -> ...
    case Pair<I>(D d1, D d2) -> ...
}

相比之下,这个switch不是完整的,因为没有匹配包含两个类型为D的值的对:

// Java 21及以后
switch (p2) {                        // 错误!
    case Pair<I>(C fst, D snd) -> ...
    case Pair<I>(D fst, C snd) -> ...
    case Pair<I>(I fst, C snd) -> ...
}

10 未来

记录模式的描述中提到了许多可以扩展这里描述的记录模式的方向:

  • 可变参数模式,用于可变数量的记录
  • 匿名模式,可以出现在记录模式的模式列表中,匹配任何值,但不声明模式变量
  • 适用于任意类的值而不仅仅是记录类的模式。

我们可以在未来的JEP中考虑其中的一些方向。

11 依赖关系

本JEP建立在Pattern Matching for instanceof(JEP 394)的基础上,该功能已在JDK 16中发布。它与Pattern Matching for switch(JEP 441)共同演进。

本文由博客一文多发平台 OpenWrite 发布!文章来源地址https://www.toymoban.com/news/detail-712113.html

到了这里,关于JDK21新特性Record Patterns记录模式详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JDK21发布了!面试官:来,谈下jdk21的新特性!

    JDK21 计划23年9月19日正式发布,尽管一直以来都是“版随意出,换 8 算我输”,但这么多年这么多版本的折腾,若是之前的 LTS 版本JDK17你还觉得不错,那 JDK21还是有必要关注一下,因为会有一批重要更新发布到生产环境中,特别是被众人期待已久的虚拟线程,纵然说这东西我

    2024年02月07日
    浏览(55)
  • JDK21新特性

    JDK8新特性 JDK9新特性 JDK10新特性 JDK11新特性 JDK12新特性 JDK13新特性 JDK14新特性 JDK15新特性 JDK16新特性 JDK17新特性 JDK18新特性 JDK19新特性 JDK20新特性 JDK21新特性 JDK 21 于 2023 年 9 月 19 日 发布,这是一个非常重要的版本,里程碑式。 JDK21 是 LTS(长期支持版),至此为止,目前有

    2024年02月22日
    浏览(51)
  • 【Java基础系列】JDK21新特性

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月04日
    浏览(43)
  • JDK8,JDK11,JDK17,JDK21及中间版本主要更新特性

    官方地址: https://www.oracle.com/java/technologies/java-se-support-roadmap.html 从上图可以很清晰得可以看出,JDK7,JDK8,JDK11,JDK17,JDK21是长期维护的版本。从目前来看,JDK8到2023年已经有将近10年的历史了,大多数依据JDK8的相关技术内容已经很成熟了,但是大家也看到,JDK在不断地迭代,JD

    2024年02月21日
    浏览(61)
  • Java/JDK 21正式发布!15个特性一览

    JDK 21已经于2023年9月19日正式发布。本文总结了JDK 21发布的新特性。 根据发布的规划,这次发布的 JDK 21 将是一个长期支持版(LTS 版)。LTS 版每 2 年发布一个,上一次长期支持版是 21 年 9 月发布的 JDK 17。 本版本是Java SE平台21版的参考实现,由Java社区流程中的JSR 396指定。 主

    2024年02月08日
    浏览(57)
  • 【收藏】35个JDK 21新特性(含示例代码)

    2024年威哥携三位兄弟,Mask、强哥、索尓一起探索Java JDK21 LTS版,JDK 21 带来了一些令人兴奋的新特性和改进,总结了一些自己的笔记,分享给大家,本文将介绍其中一些重要的内容,并提供相应的示例代码以帮助读者更好地理解,阅读全文需要花费你10分钟,收藏起来肯定有

    2024年04月15日
    浏览(44)
  • JDK8、JDK11、JDK17和JDK21这几个版本更新的主要特性

    JDK8 是 Java 的一个重大更新版本,引入了一系列新特性和改进,主要包括: Lambda 表达式: Lambda 表达式允许我们以简洁、函数式的方式编写代码,使代码更易于理解和维护。- Stream API : Stream API 提供了一套声明式处理数据的方式,使得对集合和数组的操作更加直观和高效。

    2024年04月29日
    浏览(50)
  • Java_JDK8到JDK21各版本发行时间及重要特性

    2022年Spring6和SpringBoot3相继推出,在此之前,Java社区一直是\\\"新版任你发,我用Java 8\\\",不管新版本怎么出,很少有人愿意升级。 这一次,Spring 直接来了个大招,SpringBoot3和Spring6的最低依赖就是JDK17!跨过 JDK 8-16,直接升级到 JDK 17。那么为什么是 JDK 17呢? 为什么是JDK17这么多新

    2024年01月19日
    浏览(43)
  • 【Java】JDK 21中的虚拟线程以及其他新特性

      目录 一、字符串模板(String Templates) 二、序列化集合(Sequenced Collections) 三、分代ZGC(Generational ZGC) 四、记录模式(Record Patterns) 五、Fibers(纤程) 结论 JDK 21是Java开发工具包的最新版本,它引入了许多令人振奋的新特性,旨在提高开发人员的生产力和代码质量。在本

    2024年02月08日
    浏览(47)
  • JDK 21 发布,新特性概览及字符串模板详细介绍

    Java 21 已于 2023 年 9 月 19 日发布,是 Oracle 标准 Java 实现的下一个长期支持(LTS)版本。Java 21 具有以下 15 项新特性。 430: String Templates (Preview) 字符串模板,可以像其他语言那样子方便的做字符串拼接,是+号,StringBuilder,MessageFormat之外更方便的字符串拼接方法。 431: Sequenc

    2024年02月02日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包