前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java新特性-JDK16中的Record类(怎么精简地表达不可变数据?)

Java新特性-JDK16中的Record类(怎么精简地表达不可变数据?)

作者头像
袁新栋-jeff.yuan
发布2021-12-07 17:51:11
1.2K0
发布2021-12-07 17:51:11
举报
文章被收录于专栏:用户4352451的专栏

Java新特性-JDK16中的Record类

1. 背景

从18年开始了解到java就用的就是jdk8,经历了两家公司,也都是JDK8的项目,这是故步自封还是稳中求胜呢,对于商业项目来讲需要考虑到的地方太多了,更新的价值点和风险点 ,最终的结果导向还是价值,升级后对于我们现在到底能带来多少送价值。但是对于我个人来讲我不去学习新的东西,那必然是故步自封了。

给你一个保守、粗暴的估计,你如果从 JDK 8 迁移到 JDK 17,并且能够恰当使用 JDK 8 以后的新特性的话,产品的代码量可以减少 20%,代码错误可以减少 20%,产品性能可以提高 20%,维护成本可以降低 20%。这些,都是实实在在的收益。拥抱 Java 新特性,掌握主动权------- 范学雷 (Oracle 首席软件工程师)

2. JAVA新特性-档案类

2.1 什么是档案类?

2.1.1 概括
  1. (Record)使用档案类增强 Java 编程语言,档案类(Record)是充当不可变数据的透明载体的类。记录可以被认为是名义元组
  2. 记录类是 Java 语言中的一种新类。记录类有助于用比普通类更少的仪式对普通数据聚合进行建模。 记录类的声明主要由其状态的声明组成 ;然后记录类提交到与该状态匹配的 API。这意味着记录类放弃了类通常享有的自由——将类的 API 与其内部表示分离的能力——但作为回报,记录类声明变得更加简洁。 更准确地说,记录类声明由名称、可选类型参数、标题和正文组成。标题列出了记录类的组件,它们是构成其状态的变量。(此组件列表有时称为状态描述。)
2.1.2 目标
  1. 设计一个面向对象的构造来表达简单的值聚合。
  2. 帮助开发人员专注于建模不可变数据而不是可扩展行为。
  3. 自动实现数据驱动的方法,例如equals和访问器。
  4. 保留长期存在的 Java 原则,例如名义类型和迁移兼容性。

2.2 为什么引入档案类

2.2.1 动机

人们普遍抱怨“Java 太冗长”或“仪式太多”。一些最严重的违规者是那些只不过是少数值的不可变 数据载体的类。正确编写这样一个数据载体类涉及许多低价值、重复、容易出错的代码:构造函数、访问器equalshashCodetoString、 等。

2.2.2 案例

设计一个圆形的对象:

代码语言:javascript
复制
package com.yuanxindong.study.record;

public final class Circle implements Shape {
    public final double radius;

    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }

}

设计一个方形的对象:

代码语言:javascript
复制
package com.yuanxindong.study.record;

public final class Square implements Shape {
    public final double side;

    public Square(double side) {
        this.side = side;
    }
    
    @Override
    public double area() {
        return side * side;
    }

}

本着DRY原则(dont repeat yourself),我们是否可以进一步抽象,和简化代码呢?当你看到的时候会不会想到枚举类呢?

那这个时候record类就来了:

代码语言:javascript
复制
package com.yuanxindong.study.record;

public record Circle(double radius) implements Shape {
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

可以发现我们不用,声明成员变量,也不需要构造方法了,就是多了一个类上面多了一个入参,并且其中档案类内置了缺省的 equals 方法、hashCode 方法以及 toString 方法的实现。一般情况下,我们就再也不用担心这三个方法的重载问题了。这不仅减少了代码数量,提高了编码的效率;还减少了编码错误,提高了产品的质量。

2.3 档案类的使用

2.3.1 如何声明档案类

在上文的代码中我们已经看到了record类的声明和使用,这里就不再赘述

2.3.2 java 档案类的限制(不可变数据)
  1. Java 档案类不支持扩展子句,用户不能定制它的父类。隐含的,它的父类是 java.lang.Record。父类不能定制,也就意味着我们不能通过修改父类来影响 Java 档案的行为。
  2. Java 档案类是个终极(final)类,不支持子类,也不能是抽象类。没有子类,也就意味着我们不能通过修改子类来改变 Java 档案的行为。
  3. Java 档案类声明的变量是不可变的变量。这就是我们前面反复强调的,一旦实例化就不能再修改的关键所在。
  4. Java 档案类不能声明可变的变量,也不能支持实例初始化的方法。这就保证了,我们只能使用档案类形式的构造方法,避免额外的初始化对可变性的影响。
  5. Java 档案类不能声明本地(native)方法。如果允许了本地方法,也就意味着打开了修改不可变变量的后门。
2.3.3 透明的载体
2.3.3.1 透明载体的含义

在上面我们也有提到过档案类内置了下面的这些方法缺省(默认)实现:

  1. 构造方法
  2. equals 方法
  3. hashCode 方法
  4. toString 方法
  5. 不可变数据的读取方法

透明载体的意思,通俗地说,就是档案类承载有缺省实现的方法,这些方法可以直接使用,也可以替换。

2.3.3.2 那在什么时候可以去重载这些方法呢?
  1. 重载构造方法:最常见的替换,是要在构造方法里对档案类声明的变量添加必要的检查。
  2. 重载 equals 方法:如果缺省的 equals 方法或者 hashCode 方法不能正常工作或者存在安全的问题,就需要替换掉缺省的方法。
  3. 不推荐的重载:我们有时候也需要重载 toString 方法。但是,我们通常不建议重载不可变数据的读取方法。因为,这样的重载往往意味着需要变更缺省的不可变数值,从而打破实例的状态,进而造成许多无法预料的、让人费解的后果。

3. 总结

  • 知道 Java 支持档案类,并且能够有意识地使用档案类,提高编码效率,降低编码错误;
  • 了解档案类的原理和它要解决的问题,知道使用不可变的对象优势;
  • 了解档案类的缺省方法,掌握缺省方法的好处和不足,知道什么时候要重载这些方法。

4. 引用

  • https://openjdk.java.net/jeps/395 jdk官方文档
  • https://time.geekbang.org/column/article/446610 -极客时间深入剖析java新特性
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java新特性-JDK16中的Record类
    • 1. 背景
      • 2. JAVA新特性-档案类
        • 2.1 什么是档案类?
        • 2.2 为什么引入档案类
        • 2.3 档案类的使用
      • 3. 总结
        • 4. 引用
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档