Java Lombok 详解

困惑

我们在编写一个类(常见为实体类)时,基本需要写以下代码:

  1. 类成员变量(或者称为类属性、类的字段)
  2. 默认构造函数,或带参构造函数
  3. toString 方法
  4. 类属性的 getter 和 setter 方法

比如:

package org.example.entity;

public class User {
    private Integer uid;
    private String name;
    private String pwd;
    private Integer age;

    public User() {

    }
    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

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

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

其中一个比较困恼的就是每个类的属性字段,都需要写上一遍 getXX 和 setXX 方法,少还没啥关系,多的话,就有些觉得在做无用功了(不复杂,而且可以认为是一类模板),纯属就是一件费劳动力的事。那有没有相关的工具可以避免手动写这些“无用”的代码呢?这时 Lombok 就派上用场了。

引入 Lombok

先引入 Lombok 依赖:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
    <scope>provided</scope>
</dependency>

说明:

  1. lombok 最新版本可在 https://search.maven.org/ 检索
  2. 由于我们只需要 Lombok 自动的帮我们生成一类确定的代码,而不需要包 Lombok 打包进入我们项目的 jar 包中,所以这里我们用 provided 进行限制;(provided 只在编译和测试时有效)

Lombok 注解详解

注解 描述
@Getter/@Setter 作用类上,生成所有成员变量的getter/setter方法;作用在成员变量上,生成该成员变量的getter/setter方法;可以设定访问权限以及是否懒加载等作用在成员变量上,生成该成员变量的getter/setter方法。可以设定访问权限以及是否懒加载等
@ToString 作用于类,覆盖默认的toString()方法,可以通过of属性限定显示某些字段,通过exclude属性排除某些字段
@EqualsAndHashCode 作用于类,覆盖默认的equals和hashCode
@NonNull 主要作用于成员变量和参数中,标识不能为空,否则抛出空指针异常
@NoArgsConstructor 注解在类,生成无参的构造方法
@RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段
@AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法
@Data 作用于类上,是@ToString @EqualsAndHashCode @Getter @Setter @RequiredArgsConstructor的集合,生成setter/getter、equals、canEqual、hashCode、toString方法,如果为final属性,则不会为该属性生成setter方法
@Log 作用在类上,生成日志变量。针对不同的日志实现产品,有不同的注解
@Builder 作用在类上,生成实体建造者

其中常用的注解有:@Getter/@Setter @Builder 和 @Data

其中 @Builder 一般用在 JDBC 时,给对象赋值是很方便。

代码改写

引入依然后,我们再来改写我们的代码

package org.example.entity;

import lombok.Data;

@Data
public class User {
    private Integer uid;
    private String name;
    private String pwd;
    private Integer age;
}

以上用 @Data ,此时的代码就很简洁了,我们在写个测试,看是否能访问到具体的 setter 和 getter:

package org.example;

import org.example.entity.User;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args )
    {
        User user = new User();
        user.setUid(110);
        user.setName("张三");
        user.setPwd("123");
        user.setAge(18);
        System.out.println(user);
    }
}

运行结果:

User(uid=110, name=张三, pwd=123, age=18)

Lombok 原理

Lombok 一个辅助工具,帮助开发者自动完成那些“毫无意义”且重复的代码,虽然开发者使用了 Lombok 没有人为的编写 setter 或 getter 等代码,但不表示这些代码就没有了,实际上这些代码由 Lombok 帮我们“写”了,我们可以查看编译后的字节码(User.class):

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.example.entity;

public class User {
    private Integer uid;
    private String name;
    private String pwd;
    private Integer age;

    public User() {
    }

    public Integer getUid() {
        return this.uid;
    }

    public String getName() {
        return this.name;
    }

    public String getPwd() {
        return this.pwd;
    }

    public Integer getAge() {
        return this.age;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                label59: {
                    Object this$uid = this.getUid();
                    Object other$uid = other.getUid();
                    if (this$uid == null) {
                        if (other$uid == null) {
                            break label59;
                        }
                    } else if (this$uid.equals(other$uid)) {
                        break label59;
                    }

                    return false;
                }

                Object this$age = this.getAge();
                Object other$age = other.getAge();
                if (this$age == null) {
                    if (other$age != null) {
                        return false;
                    }
                } else if (!this$age.equals(other$age)) {
                    return false;
                }

                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                Object this$pwd = this.getPwd();
                Object other$pwd = other.getPwd();
                if (this$pwd == null) {
                    if (other$pwd != null) {
                        return false;
                    }
                } else if (!this$pwd.equals(other$pwd)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $uid = this.getUid();
        result = result * 59 + ($uid == null ? 43 : $uid.hashCode());
        Object $age = this.getAge();
        result = result * 59 + ($age == null ? 43 : $age.hashCode());
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        Object $pwd = this.getPwd();
        result = result * 59 + ($pwd == null ? 43 : $pwd.hashCode());
        return result;
    }

    public String toString() {
        return "User(uid=" + this.getUid() + ", name=" + this.getName() + ", pwd=" + this.getPwd() + ", age=" + this.getAge() + ")";
    }
}

从以上的字节码可以看出,setter 和 getter 等方法是存在的,这些都是有 Lombok 在编译阶段生成的。

发表评论