Java新特性-JDK16中的Record类(怎么精简地表达不可变数据?)
Posted Jeff、yuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java新特性-JDK16中的Record类(怎么精简地表达不可变数据?)相关的知识,希望对你有一定的参考价值。
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 概括
-
(Record)使用档案类增强 Java 编程语言,档案类(Record)是充当不可变数据的透明载体的类。记录可以被认为是名义元组。
-
记录类是 Java 语言中的一种新类。记录类有助于用比普通类更少的仪式对普通数据聚合进行建模。
记录类的声明主要由其状态的声明组成 ;然后记录类提交到与该状态匹配的 API。这意味着记录类放弃了类通常享有的自由——将类的 API 与其内部表示分离的能力——但作为回报,记录类声明变得更加简洁。
更准确地说,记录类声明由名称、可选类型参数、标题和正文组成。标题列出了记录类的组件,它们是构成其状态的变量。(此组件列表有时称为状态描述。)
2.1.2 目标
- 设计一个面向对象的构造来表达简单的值聚合。
- 帮助开发人员专注于建模不可变数据而不是可扩展行为。
- 自动实现数据驱动的方法,例如
equals
和访问器。 - 保留长期存在的 Java 原则,例如名义类型和迁移兼容性。
2.2 为什么引入档案类
2.2.1 动机
人们普遍抱怨“Java 太冗长”或“仪式太多”。一些最严重的违规者是那些只不过是少数值的不可变 数据载体的类。正确编写这样一个数据载体类涉及许多低价值、重复、容易出错的代码:构造函数、访问器equals
、hashCode
、toString
、 等。
2.2.2 案例
设计一个圆形的对象:
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;
设计一个方形的对象:
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类就来了:
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 档案类的限制(不可变数据)
- Java 档案类不支持扩展子句,用户不能定制它的父类。隐含的,它的父类是 java.lang.Record。父类不能定制,也就意味着我们不能通过修改父类来影响 Java 档案的行为。
- Java 档案类是个终极(final)类,不支持子类,也不能是抽象类。没有子类,也就意味着我们不能通过修改子类来改变 Java 档案的行为。
- Java 档案类声明的变量是不可变的变量。这就是我们前面反复强调的,一旦实例化就不能再修改的关键所在。
- Java 档案类不能声明可变的变量,也不能支持实例初始化的方法。这就保证了,我们只能使用档案类形式的构造方法,避免额外的初始化对可变性的影响。
- Java 档案类不能声明本地(native)方法。如果允许了本地方法,也就意味着打开了修改不可变变量的后门。
2.3.3 透明的载体
2.3.3.1 透明载体的含义
在上面我们也有提到过档案类内置了下面的这些方法缺省(默认)实现:
- 构造方法
- equals 方法
- hashCode 方法
- toString 方法
- 不可变数据的读取方法
透明载体的意思,通俗地说,就是档案类承载有缺省实现的方法,这些方法可以直接使用,也可以替换。
2.3.3.2 那在什么时候可以去重载这些方法呢?
- 重载构造方法:最常见的替换,是要在构造方法里对档案类声明的变量添加必要的检查。
- 重载 equals 方法:如果缺省的 equals 方法或者 hashCode 方法不能正常工作或者存在安全的问题,就需要替换掉缺省的方法。
- 不推荐的重载:我们有时候也需要重载 toString 方法。但是,我们通常不建议重载不可变数据的读取方法。因为,这样的重载往往意味着需要变更缺省的不可变数值,从而打破实例的状态,进而造成许多无法预料的、让人费解的后果。
3. 总结
-
知道 Java 支持档案类,并且能够有意识地使用档案类,提高编码效率,降低编码错误;
-
了解档案类的原理和它要解决的问题,知道使用不可变的对象优势;
-
了解档案类的缺省方法,掌握缺省方法的好处和不足,知道什么时候要重载这些方法。
4. 引用
- https://openjdk.java.net/jeps/395 jdk官方文档
- https://time.geekbang.org/column/article/446610 -极客时间深入剖析java新特性
以上是关于Java新特性-JDK16中的Record类(怎么精简地表达不可变数据?)的主要内容,如果未能解决你的问题,请参考以下文章