Java原生支持Lombok了,你知道吗?

开发 前端
Record类和record关键字的引入,极大地提升了定义类的便捷性,打破了Java语言规范中POJO类冗长的声明。我们可以不用他,但是要知道其用法。就像是Java8的stream一样,Record类也有很大魅力。

你好,我是看山。

我们在开发时会借助Lombok快速填充POJO类的模板方法,比如:getter、setter、equals、hashCode等,引入这个组件的原因是方便,一个注解就可以代理一堆的模板方法。

从Java16开始,我们可以借助Record类型实现相同的功能了,接下来,我们详细看下这个类型。

Record是Java中的一种特殊类,旨在为程序员提供一种高效且简便的方式实现POJO类。Record类型通过关键字record实现。

一、Java中的Record类是什么?

在Java项目开发中,作为开发者,我们常常编写服务类、安全类或其他基础类,这些类本质上是功能性的。同样,程序员也经常编写仅用于承载数据的类,即POJO类。

例如,假设客户端向服务器请求某个人的“id”和“name”等数据,服务器会以相应的数据进行响应。

由于Java中一切皆为对象,所以必然存在某个类来承载这些数据,服务器会将该类的对象返回给客户端,该对象的唯一目的就是将数据从服务器传递到客户端。

然而,编写这样一个数据类,即便它可能只是一个简单的POJO,也会包含大量的模板代码,比如私有字段、构造函数、getter和setter方法、hashCode()、equals()和toString()方法。

由于Java语言的冗长特性,一个简单的承载类会因大量不必要的代码而变得臃肿。

这些弊端促使了一种特殊类型的类Record的诞生。该类能够聚合(或持有)一组值,无需编写自动生成样板代码,可以说是一种高效的数据对象构建方式。

虽然,即使没有Record类型,我们也能写好代码,比如借助IDEA的模板生成,比如借助Lombok的注解,但是,原生支持的能力,在便利性和效率方面,可以给代码注入新的灵魂。

我们看下以前的写法:

import java.util.Objects;

public class Person {
    private int id;
    private String name;

    public Person() {}

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass()!= o.getClass()) return false;
        Person person = (Person) o;
        return getId() == person.getId() && getName().equals(person.getName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId(), getName());
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

是不是看着都不想写了。

二、如何在Java中创建Record类?

Java中的Record类由关键字record支持,语法为:

record recordName(list-of-components) {
    //可选语句
}

以record开头,后面跟着类名和参数列表。此时,我们可以把前面的Person改写为:

record Person(int id, String name){}

一下子就清爽了。

使用起来和原来没有太多差异:

Person p1 = new Person(1, "Peter Parker");

在编译过程中,编译器会自动提供存储数据所需的元素、构造函数、访问数据的getter方法、toString()、equals()和hashCode()方法。因此,虽然没有写下面这些方法,也能够正常使用。

Person p1 = new Person(1, "Peter Parker");
Person p2 = new Person(2, "Spiderman");
System.out.println(p1.toString());
System.out.println(p1.equals(p2));
System.out.println(p1.name());

关于上述代码示例,有以下几个要点需要注意:

  • Record类提供的规范构造函数包含与组件列表中传递的相同参数,且顺序一致。传递的值会自动赋给记录字段。
  • Record类通过“new”关键字进行实例化,就像在Java中创建其他任何对象一样。
  • Record类中的数据保存在私有final字段中,并且只有getter方法。因此,记录中的数据是不可变的。
  • Record类不能继承其他类。是因为已经隐式继承java.lang.Record。并重写了Object类的equals()、hashCode()和toString()方法。
  • Record类声明都是final的,所以它们不能被扩展。
  • Record类可以实现一个或多个接口。
  • 除了声明的参数外,任何其他字段必须声明为静态的。

三、Java中的规范构造函数

在Record中,如果需要定义规范构造函数,需要按照预设格式定义。我们有两种方式来声明我们自己的实现。

方式一、常用的规范构造函数:

record Invoice(String id, float amount) {
    static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
            + String.valueOf(Calendar.getInstance().get(Calendar.MONTH) + 1);

    public Invoice(String id, float amount) {
        this.id = prefix + id.trim();
        this.amount = amount;
    }
}

方式二、紧凑构造函数。在紧凑构造函数中,签名声明是隐式的。我们只需提供Record类名作为构造函数,不带任何参数。这种类型的构造函数具有所有参数的隐式声明,并且会自动将传递给记录组件的值赋给相应参数。此外,在紧凑构造函数中,不使用this关键字。

record Invoice(String id, float amount) {
    static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
            + String.valueOf(Calendar.getInstance().get(Calendar.MONTH) + 1);
    public Invoice {
        id = prefix + id.trim();
        amount = amount;
    }  
}

四、Java中的非规范构造函数

除了规范构造函数,我们还可以定义非规范构造函数。比如:当我们只想用默认初始化一个字段,此时,我们可以编写一个非规范构造函数。

非规范构造函数的关键要求是,构造函数必须使用this关键字调用记录中的另一个规范构造函数。

以下是一个简单示例:

record Invoice(String id, float amount) {
    static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
            + String.valueOf(Calendar.getInstance().get(Calendar.MONTH) + 1);
    public Invoice {
        id = prefix + id.trim();
        amount = amount;
    }

    public Invoice(String id) {
        this(id, 0.0f);
    }
}

非规范构造函数就像是预设默认值的一种实现。

五、Java Record类代码示例

最后,我们来个示例代码,展示了如何在Java中使用Record类、规范构造函数和非规范构造函数:

record Invoice(String id, float amount) {
    static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
            + String.valueOf(Calendar.getInstance().get(Calendar.MONTH) + 1);
    public Invoice {
        id = prefix + id.trim();
        if (amount < 0)
            throw new IllegalArgumentException("-ve values not allowed");
        amount = amount;
    }

    public Invoice(String id) {
        this(id, 0.0f);
    }
}

public class App {
    public static void main(String[] args) {
        float[] amt = {400.00f, 600.00f, 300.00f, 700.00f, 600.00f};
        Invoice[] invoice = new Invoice[5];
        for (int i = 0; i < invoice.length; i++)
            invoice[i] = new Invoice(String.valueOf(i + 1), amt[i]);
        for (int i = 0; i < invoice.length; i++)
            System.out.println(invoice[i].toString());
    }
}

文末总结

Record类和record关键字的引入,极大地提升了定义类的便捷性,打破了Java语言规范中POJO类冗长的声明。我们可以不用他,但是要知道其用法。就像是Java8的stream一样,Record类也有很大魅力。

责任编辑:武晓燕 来源: 看山的小屋
相关推荐

2024-04-07 00:00:03

2019-06-06 15:00:25

手机iPhone摩托罗拉

2024-10-12 08:01:53

2024-10-09 08:54:31

2021-10-08 11:13:41

子集问题数据结构算法

2018-12-27 08:50:06

JavaScript开源

2024-04-07 00:00:00

ESlint命令变量

2024-05-28 09:12:10

2024-04-30 09:02:48

2023-12-12 08:41:01

2023-12-20 08:23:53

NIO组件非阻塞

2023-04-26 10:21:04

2022-12-02 14:12:52

新能源汽车海尔

2022-11-04 14:16:05

2024-07-08 00:00:01

多线程ThreadC#

2024-09-18 07:00:00

消息队列中间件消息队列

2022-09-29 15:32:58

云计算计算模式

2020-02-20 08:30:49

OSPF网络协议路由协议

2021-04-20 23:16:06

SparkSQL语法

2023-01-13 17:02:10

操作系统鸿蒙
点赞
收藏

51CTO技术栈公众号