分类
标签
Bash C/C++ CI/CD CMU Cookie CS231n CS50 CSS CTF Diffie-Hellman Emmet Floyd算法 FPGA GitHub Actions Github Pages golang GOT表 Hexo HTML HTTP Java JavaScript Jupyter LeetCode Linux logrus MIT Missing Semester NumPy OpenSSL PLT表 Python RSA Session Shell sing-box socket SQL SQLite SQL注入 SVD SymPy TCP/IP Verilog Web开发 writeup XPath ZJU校巴 主定理 代理 信息安全 内存 前端 动态规划 动态链接 博客 压缩 参考 后端 命令行 国际交流 图像处理 图解 堆 堆排序 复杂度分析 密码学 开发 归并排序 微积分 心得 快速排序 抽象代数 搜索 操作系统 数字电路 数字逻辑 数学 数据库 数据结构 数论 文件系统 时间戳 有限状态自动机 机器学习 正则表达式 汇编 游戏开发 爬虫 物理 环境配置 科学计算 竞赛 笔记 算法 线性代数 编程语言 编译 网络 网络安全 背包DP 计算机基础 计算机视觉 计算机网络 课程 课程推荐 谱定理 踩坑 逆向 逆向工程 逻辑电路 非对称加密 题解 高斯消元法 魔塔
861 字
4 分钟
用Java中的Record简化代码
简介
Record是从Java 14开始引入的新特性,Record提供了一种简洁高效的方式来创建不可变类。
引入
使用Java进行开发的时候,程序员经常会创建一些不可变类专门用于承载数据(也就是MVC模型中的model),这些类可能涉及大量的样板代码,包括:
- 大量的
private
、final
、public
关键字 - 每个字段的getter
- 重写
equals()
、hashCode()
、toString()
方法
例如以下代码
package example;
import java.util.Objects;
public final class Person {
private final Long id;
private final String name;
private final Integer age;
// 构造函数
public Person(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
// Getter
public Long getId() {
return id;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
// equals 方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person user = (Person) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name) &&
Objects.equals(age, user.age);
}
// hashCode 方法
@Override
public int hashCode() {
return Objects.hash(id, name, age);
}
// toString 方法
@Override
public String toString() {
return "Person[" +
"id=" + id +
", name=" + name + '\'' +
", age='" + age + '\'' +
']';
}
}
使用record
类就可以简化为
package example;
public record Person (
Long id,
String name,
Integer age
) {}
record类的特性
- 自动生成带有所有参数的构造方法
- 自动生成每一个字段的getter方法,使用同名的
public
方法。 - 没有setter方法,这是因为记录类是不可变的
- 自动重写
toString()
方法,具体逻辑参考第一种Person
类代码 - 自动重写
hashCode()
方法 - 自动重写
equals()
方法,判定两个对象相等当且仅当二者类型相同,且每个字段都相等 - 每一个属性都是
final
,不可修改 final
类,不可被继承
定义
package example;
//访问修饰符 record 类名(字段列表)
public record Student(
Long id,
String name,
Double englishScore,
Double mathScore
)
{
//可以增加static字段
public static int count = 0;
//不可以增加实例变量(非静态属性)
//private boolean thisIsNotAllowed = true;
//可以自己写构造函数,如果没有写,record类默认会从参数赋值所有字段
public Student {
// 不用写这些代码,他们是自动的
// this.id = id;
// this.name = name;
// this.englishScore = englishScore;
// this.mathScore = mathScore;
count++;
}
//可以额外增加成员方法
public Double score() {
return englishScore * 0.4 + mathScore * 0.6;
}
}
解释一下上面的构造函数,实际上这段代码
public Student {
count++;
}
和以下代码是等价的
public Student(Long id, String name, Double englishScore, Double mathScore) {
this.id = id;
this.name = name;
this.englishScore = englishScore;
this.mathScore = mathScore;
count++;
}
是不是很方便!
使用
运行以下代码
package example;
public class Main {
public static void main(String[] args) {
Student student = new Student(1L, "cyrus28214", 60.0, 70.0);
Student student2 = new Student(1L, "cyrus28214", 60.0, 70.0);
System.out.println(Student.count);
System.out.println(student.equals(student2));
System.out.println(student.hashCode());
System.out.println(student.toString());
System.out.println(student.name());
System.out.println(student.score());
}
}
将输出
2
true
1360019156
Student[id=1, name=cyrus28214, englishScore=60.0, mathScore=70.0]
cyrus28214
66.0
作用
record可以极大简化不可变类的代码,而不可变类在JPA中非常常见,所以可以利用record来写JPA:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "users")
public record User (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id,
String username,
String passwordHash
) {}
与传统的写法来说,可以少写很多代码,拯救你的手指。
更多支持的功能
record类还支持以下功能,和正常的类的使用方法是一致的:
- 使用泛型
- 实现接口
- 添加注解
- 序列化和反序列化
- 作为局部类(Local Class)使用
- 嵌套定义
- 支持
instanceof