Java Record

Java14 中预览的新特性叫做 Record,在 Java 中,Record 是一种特殊类型的 Java 类。可用来创建不可变类,语法

简短。参考JEP 395. Jackson 2.12 支持 Record 类

任何时候创建 Java 类,都会创建大量的样板代码,我们可能做如下:

  • 每个字段的 set,get 方法
  • 公共的构造方法
  • 重写 hashCode, toString(), equals()方法

Java Record 避免上述的样板代码,如下特点:

  • 带有全部参数的构造方法
  • public 访问器
  • toString(),hashCode(),equals()
  • 无 set,get 方法。没有遵循 Bean 的命名规范
  • final 类,不能继承 Record,Record 为隐士的 final 类。除此之外与普通类一样
  • 不可变类,通过构造创建 Record
  • final 属性,不可修改
  • 不能声明实例属性,能声明 static 成员

Record使用

IDEA 新建 Class,选择类 Record

step1: 创建 Student Record

public record Student(Integer id,String name,String email,Integer age) {
}

step2:创建 Record 对象

public void test(String[] args) {
//创建Record对象
Student lisi = new Student(1001,"lisi","lisi@qq.com",20);
System.out.println("lisi = " + lisi);
//public方法,获取属性值,只读,没有set,get方法
Integer id = lisi.id();
String name = lisi.name();
String email = lisi.email();
Integer age = lisi.age();
System.out.println("id = " + id);
}

现在能查看控制台输出:

Record 通过构造方法创建了只读的对象,能够读取每个属性,不能设置新的属性值。 Record 用于创建不可变的对象,同时减少了样板代码。Record 对每个属性提供了 public 访问器,例如 lisi.name()。

Instance Methods

Record 是 Java 类,和普通 Java 类一样定义方法。下面定义方法 concat,将姓名和年龄一起打印输出。

我们创建普通的方法 concat,将 name 和 age 连接为一个字符串输出。

step1:创建实例方法

public record Student(Integer id,String name,String email,Integer age) {
public String concat(){
return String.format("姓名:%s,年龄是:%d", this.name,this.age);
}
}

step2: 调用实例方法

@Test
public void test02() {
Student student = new Student(1001, "lisi", "lisi@qq.com", 20);
//使用对象,调用实例方法
String str = student.concat();
System.out.printf("str =" + str);
}

最后控制台输出:

静态方法 Static Method

Record 类定义静态方法,试用静态方法与普通类一样。

step1: 创建静态方法

public record Student(Integer id,String name,String email,Integer age) {
public String concat(){
return String.format("姓名:%s,年龄是:%d", this.name,this.age);
}
/** 静态方法 */
public static String emailUpperCase(String email){
return Optional.ofNullable(email).orElse("no email").toUpperCase();
}
}

step2:测试静态方法

@Test
public void test03() {
//使用类,静态方法
String email = Student.emailToUppreCase("lisi@qq.com");
System.out.println("eamil = " + email);
}

Record 的构造方法

我们可以在 Record 中添加构造方法, 有三种类型的构造方法分别:是紧凑的,规范的和定制构造方法

  • 紧凑型构造方法没有任何参数,甚至没有括号。
  • 规范构造方法是以所有成员作为参数
  • 定制构造方法是自定义参数个数

step1: 紧凑和定制构造方法

public record Student(Integer id,String name,String email,Integer age) {
/*紧凑构造方法*/
public Student{
System.out.println("id = "+ id);
if(id<1){
throw new RuntimeException("id<1");
}
}
/*自定义构造方法*/
public Student(Integer id,String name){
this(id,name,null,null);
}
}

测试:

    @Test
public void test04() {
Student student = new Student(1001,"lisi");
System.out.println("student = " + student);
}

查看编译后的class文件(紧凑构造方法和规范构造方法合并了 ):

Record 与 与 Lombok

  • Java Record 是创建不可变类且减少样板代码的好方法。Lombok 是一种减少样板代码的工具。两者有表面上的重叠部分。可能有人会说 Java Record 会代替 Lombok. 两者是有不同用途的工具。
  • Lombok 提供语法的便利性,通常预装一些代码模板,根据您加入到类中的注解自动执行代码模板。这样的库纯粹是为了方便实现 POJO 类。通过预编译代码。将代码的模板加入到 class 中。
  • Java Record 是语言级别的,一种语义特性,为了建模而用,数据聚合。简单说就是提供了通用的数据类,充当“数据载体",用于在类和应用程序之间进行数据传输。

Record 实现接口

Java Record 可以与普通类一样实现接口,重写接口的方法。

step1: 创建新的接口,定义一个规范方法。

public interface PrintInterface {
//输出自定义信息
void print();
}

step2: 创建新的 Record 实现接口,重写接口的方法,实现当前 Record 有关的业务逻辑

public record ProductRecord(Integer id, String name, Integer qty) implements PrintInterface {
@Override
public void print() {
StringJoiner joiner = new StringJoiner("-");
StringJoiner s = joiner.add(id.toString()).add(name).add(qty.toString());
System.out.println("商品信息 = " + s); }
}

ProductRecord 实现 print()方法,打印商品详情。

step3:测试 print 方法

    @Test
public void test05() {
ProductRecord productRecord = new ProductRecord(1001,"手机",200);
productRecord.print();
}

Local Record

Record 可以作为局部对象使用。在代码块中定义并使用 Record,下面定义一个 SaleRecord

step1:定义 Local Record

public static void main(String[] args) {
//定义 Java Record
record SaleRecord(String saleId,String ProductName,Double money){};
//创建 Local Record
SaleRecord saleRecord = new SaleRecord("S001","显示器",3000.01);
//使用 SaleRecord
System.out.println("saleRecord = " + saleRecord);
}

控制台输出:

嵌套 Record

多个 Record 可以组合定义, 一个 Record 能够包含其他的 Record。

我们定义 Record 为 Customer,存储客户信息,包含了 Address 和 PhoneNumber 两个 Record

step1:定义 Record

public record Address(String city,String address,String zipCode) {
}
public record Customer(String id, String name, PhoneNumber phoneNumber, Address address) {

}
public record PhoneNumber(String areaCode,String number) {
}

step2: 创建 Customer 对象

@Test
public void test07() {
Address address = new Address("大连","旅顺口区兴发路216号","10010");
PhoneNumber phoneNumber = new PhoneNumber("010","400-8080-105");
Customer customer = new Customer("C1001","李四",phoneNumber,address);
System.out.println("customer = " + customer);
String number = customer.phoneNumber().number();
System.out.println("number = " + number);
String address1 = customer.address().address();
System.out.println("address1 = " + address1);
}

控制台输出:

instanceof 判断 Record 类型

instanceof 能够与 Java Record 一起使用。编译器知道记录组件的确切数量和类型。

step1:声明 Person Record,拥有两个属性 name 和 age

public record Person(String name,Integer age) {

}

step2: 在一个业务方法判断当是 Record 类型时,继续判断 age 年龄是否满足 18 岁。

public class SomeService {
//定义业务方法,判断年龄是否18
public boolean isEligible(Object obj){
//判断 obj 为 Person 记录类型
if( obj instanceof Person(String name, Integer age)){
return age >= 18;
}
return false;
}
}

instanceof 还可以下面的方式

if( obj instanceof Person(String name, Integer age) person){
return person.age() >= 18;
}
或者
if( obj instanceof Person p){
return p.age() >= 18;
}

step3: 测试代码

@Test
public void test08() {
Person person = new Person("李四",20);
SomeService someService = new SomeService();
boolean flag = someService.isEligible(person);
System.out.println("flag = " + flag);
}

控制台输出:

处理判断中 Record 为 null

Java Record 能够自动处理 null。

step1:record 为 null

@Test
public void test09() {
SomeService someService = new SomeService();
boolean flag = someService.isEligible(null);
System.out.println("flag = " + flag);
}

控制台输出 eligible 为 false ,Debug 调试代码,发现 if 语句判断为 false,不执行

总结

  • abstract 类 java.lang.Record 是所有 Record 的父类。
  • 有对于 equals(),hashCode(),toString()方法的定义说明
  • Record 类能够实现 java.io.Serializable 序列化或反序列化
  • Record 支持泛型,例如 record Gif( T t )
  • java.lang.Class 类与 Record 类有关的两个方法:

boolean isRecord() : 判断一个类是否是 Record 类型

RecordComponent[] getRecordComponents():Record 的数组,表示此记录类的所有记录组件

@Test
public void test10() {
Address address = new Address("大连","旅顺口区兴发路216号","10010");
PhoneNumber phoneNumber = new PhoneNumber("010","400-8080-105");
Customer customer = new Customer("C1001","李四",phoneNumber,address);
//判断其是否为java record类型
boolean record = customer.getClass().isRecord();
System.out.println("record = " + record);
RecordComponent[] recordComponents = customer.getClass().getRecordComponents();
for(RecordComponent recordComponent :recordComponents){
System.out.println("recordComponent = " + recordComponent);
}



公众号本文地址:https://mp.weixin.qq.com/s/JNytIhxe-a-VOmq3fV4aag

欢迎关注公众号:愚生浅末

JDK有用的新特性-Java Record的更多相关文章

  1. Java JDK 1.7 和 JDK 1.8 新特性

    0 引言 本文主要介绍 Java JDK 中 1.7 和 1.8 的新特性. 1 JDK 1.7 新特性 1. switch可以接受String类型: public class Switch { pu ...

  2. JDK 5 ~ 10 新特性倾情整理!

    JDK 5 ~ 10 新特性倾情整理! 最近连 JDK11都在准备发布的路上了,大家都整明白了吗?也许现在大部分人还在用6-8,8的新特性都没用熟,9刚出不久,10-11就不用说了. 为了大家对JDK ...

  3. JDK 14的新特性:更加好用的NullPointerExceptions

    JDK 14的新特性:更加好用的NullPointerExceptions 让99%的java程序员都头痛的异常就是NullPointerExceptions了.NullPointerExceptio ...

  4. 译文《全新首发JDK 16全部新特性》

    封面:洛小汐 译者:潘潘 JDK 8 的新特性都还没摸透,JDK 16 的新特性就提着刀来了. 郑重申明: 第一次冒险翻译专业领域的文献,可想而知,效果特别糟糕.一般翻译文献特别是 技术专业领域 的内 ...

  5. java8 (jdk 1.8) 新特性——Lambda

    java8 (jdk 1.8) 新特性 --初步认识 1. 什么是lambda? 目前已知的是,有个箭头  -> 说一大段官方话,也没有任何意义 我们直接看代码: 之前我们创建线程是这样的 Ru ...

  6. Atitit swt 4.3 4.4 4.5 新特性java attilax总结

    Atitit swt 4.3 4.4 4.5 新特性java attilax总结 1. 4.5 Release - June 3, 20151 1.1. Older Releases1 2. SWT  ...

  7. JDK 14的新特性:instanceof模式匹配

    JDK 14的新特性:instanceof模式匹配 JDK14在2020年的3月正式发布了.可惜的是正式特性只包含了最新的Switch表达式,而Records,patterns,text blocks ...

  8. Java 16 新特性:record类

    以前我们定义类都是用class关键词,但从Java 16开始,我们将多一个关键词record,它也可以用来定义类.record关键词的引入,主要是为了提供一种更为简洁.紧凑的final类的定义方式. ...

  9. JDK各版本新特性!

    1.JDK1.5 新特性 1.自动装箱与拆箱:自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中.自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动地提取 ...

  10. Java SE 6 新特性: Java DB 和 JDBC 4.0

    http://www.ibm.com/developerworks/cn/java/j-lo-jse65/index.html 长久以来,由于大量(甚至几乎所有)的 Java 应用都依赖于数据库,如何 ...

随机推荐

  1. vue3 'alex' is defined but never used

    解决方法 在package.json中的rules下加入 "no-unused-vars":"off" 即可

  2. java将list中某个元素放在首位

    java将list中某个元素放在首位 1 List<Example> example = exampleRepository.list(); 2 3 //将list里的某个字符串默认排列在 ...

  3. springboot实现异步调用demo

    springboot实现异步调用 异步调用特点 异步调用在开发程序中被广泛应用,在异步任务中,主线程不需要阻塞等待异步任务的完成,而是可以继续处理其他请求. 异步调用的特点如下: 非阻塞:主线程在调用 ...

  4. 历代iPhone及Android手机的屏幕参数对比

    手机逻辑分辨率Point,也就是CSS像素,是进行网页适配的关键,以下是平时整理的一些备忘录数据,可以收藏. 屏幕清晰度分类 SD标清 HD高清(2倍屏) FHD全高清(3倍屏) QHD倍高清(4倍屏 ...

  5. [oeasy]python0093_电子游戏起源_视频游戏_达特茅斯_Basic_家酿俱乐部

    编码进化 回忆上次内容 Ed Robert 的 创业之路 从 售卖 diy 组装配件 到进军 计算器市场 最后 发布 牛郎星8800 intel 8080 的出现 让 人人都有 自己的 个人电脑 Bi ...

  6. 靶机练习: y0usef

    靶机: y0usef 准备工作 靶机地址: https://download.vulnhub.com/y0usef/y0usef.ova MD5 校验:28c5d869b003be94b2d8ab4b ...

  7. Django 不通过外键实现多表关联查询

    Django不通过外键实现多表关联查询 by:授客 QQ:1033553122 测试环境 Win 10   Python 3.5.4   Django-2.0.13.tar.gz 需求 不通过外键,使 ...

  8. HTML+JavaScript+CSS做一个界面

    下面是一个web界面主要是前端没有后端功能:关于JavaScript几种比较常见的样式   Javaweb(1),html <!DOCTYPE html> <html lang=&q ...

  9. Python的GDAL库绘制多波段、长时序遥感影像时间曲线图

      本文介绍基于Python中的gdal模块,对大量长时间序列的栅格遥感影像文件,绘制其每一个波段中.若干随机指定的像元的时间序列曲线图的方法.   在之前的文章中,我们就已经介绍过基于gdal模块, ...

  10. Continue-AI编程助手本地部署llama3.1+deepseek-coder-v2

    领先的开源人工智能代码助手.您可以连接任何模型和任何上下文,以在 IDE 内构建自定义自动完成和聊天体验 推荐以下开源模型: 聊天:llama3.1-8B 推理代码:deepseek-coder-v2 ...