Lombok 简单讲解

参考

https://blog.csdn.net/ThinkWon/article/details/101392808
https://www.baeldung.com/intro-to-project-lombok
https://projectlombok.org/features/

介绍

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

添加依赖:

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

在 idea 中需要确保安装了 Lombok 插件。

基本用法

生成 get 和 set 方法

使用 Lombok 的 @Getter 和 @Setter 方法,可以自动为我们生成 get 和 set 方法。

import lombok.Getter;
import lombok.Setter;

public class Person {
    @Getter
    @Setter
    private String name;
    private int age;
    private String address;
}

编译后的代码:

public class Person {
    private String name;
    private int age;
    private String address;

    public Person() {
    }

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

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

toString 方法

使用 Lombok 中的 @ToString 方法会自动为我们生成 toString 方法。

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@ToString
public class Person {
    @Getter
    @Setter
    private String name;
    private int age;
    private String address;
}

编译后的代码:

public class Person {
    private String name;
    private int age;
    private String address;

    public Person() {
    }

    public String toString() {
        return "Person(name=" + this.getName() + ", age=" + this.age + ", address=" + this.address + ")";
    }

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

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

equals 和 hashCode 方法

@EqualsAndHashCode 注解会同时生成 equals 方法和 hashCode 方法。

@EqualsAndHashCode
public class Address {
    private String street;
    private String city;
    private String state;
    private String postalCode;
}

编译后的代码:

public class Address {
    private String street;
    private String city;
    private String state;
    private String postalCode;

    public Address() {
    }

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

                    return false;
                }

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

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

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

                return true;
            }
        }
    }

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

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $street = this.street;
        result = result * 59 + ($street == null ? 43 : $street.hashCode());
        Object $city = this.city;
        result = result * 59 + ($city == null ? 43 : $city.hashCode());
        Object $state = this.state;
        result = result * 59 + ($state == null ? 43 : $state.hashCode());
        Object $postalCode = this.postalCode;
        result = result * 59 + ($postalCode == null ? 43 : $postalCode.hashCode());
        return result;
    }
}

构造方法

@NoArgsConstructor:生成无参构造方法。
@AllArgsConstructor:生成所有字段的构造方法。
@RequiredArgsConstructor:当你在一个类中使用 @RequiredArgsConstructor 注解时,Lombok 会自动帮你生成一个构造函数,该构造函数仅包含类中定义的 final 字段或者被 @NonNull 注解标记的字段。

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private int id;
    private String name;
    private String department;
    private double salary;
}

编译后的 java 代码:

public class Employee {
    private int id;
    private String name;
    private String department;
    private double salary;

    public Employee(int id, String name, String department, double salary) {
        this.id = id;
        this.name = name;
        this.department = department;
        this.salary = salary;
    }

    public Employee() {
    }
}
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

import java.util.List;

@RequiredArgsConstructor
public class Order {
    private final int orderId;
    private List<String> products;
    @NonNull
    private double totalPrice;
}

编译后的代码:

import com.jxd.bug.Product;
import java.util.List;
import lombok.NonNull;

public class Order {
    private final int orderId;
    private List<Product> products;
    private @NonNull double totalPrice;

    public Order(int orderId, @NonNull double totalPrice) {
        this.orderId = orderId;
        this.totalPrice = totalPrice;
    }
}

高级用法

日志

lombok 提供了 @Slf4j、@Log、@CommonsLog、@Log4j、@Log4j2、@XSlf4j、@Slf4j 这些日志注解来对应不同的日志框架。

import lombok.extern.slf4j.Slf4j;

/**
 * @author jxd
 * {@code @date} 2024/3/26 21:47
 */
@Slf4j
public class Log {
    public static void main(String[] args) {
        log.info("@Slf4j annotation");
    }
}

编译后的代码:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log {
    private static final Logger log = LoggerFactory.getLogger(Log.class);

    public Log() {
    }

    public static void main(String[] args) {
        log.info("@Slf4j annotation");
    }
}

@Data 注解

相当于这些注解的一个聚合:

  • @ToString
  • @EqualsAndHashCode
  • @Getter
  • @Setter
  • @RequiredArgsConstructor

@Builder 注解

@Builder 注解会自动为我们生成 bean 对应的 Builder,有了这个 Builder,就可以使用通过链式调用的方式来构建对象(建造者模式)。

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class Customer {
    private String customerId;
    private String name;
    private String email;
    private String phoneNumber;
}

编译后的代码:

public class Customer {
    private String customerId;
    private String name;
    private String email;
    private String phoneNumber;

    Customer(String customerId, String name, String email, String phoneNumber) {
        this.customerId = customerId;
        this.name = name;
        this.email = email;
        this.phoneNumber = phoneNumber;
    }

    public static CustomerBuilder builder() {
        return new CustomerBuilder();
    }

    public String toString() {
        return "Customer(customerId=" + this.customerId + ", name=" + this.name + ", email=" + this.email + ", phoneNumber=" + this.phoneNumber + ")";
    }

    public static class CustomerBuilder {
        private String customerId;
        private String name;
        private String email;
        private String phoneNumber;

        CustomerBuilder() {
        }

        public CustomerBuilder customerId(String customerId) {
            this.customerId = customerId;
            return this;
        }

        public CustomerBuilder name(String name) {
            this.name = name;
            return this;
        }

        public CustomerBuilder email(String email) {
            this.email = email;
            return this;
        }

        public CustomerBuilder phoneNumber(String phoneNumberCu

使用 Builder 去构造 Customer 对象:

import org.junit.jupiter.api.Test;

/**
 * @author jxd
 * {@code @date} 2024/3/26 22:05
 */
public class UseCustomer {
    @Test
    public void useBuilder() {
        final Customer tom = new Customer.CustomerBuilder()
                .email("example.163.com")
                .customerId("1")
                .phoneNumber("1121")
                .name("tom")
                .build();
        System.out.println(tom);
    }
}

懒加载

@Getter(lazy = true)

常见坑

boolean 类型的字段

@Data
public class Product {
    private String name;
    private double price;
    private String description;
    /**
     * boolean 类型的字段会生成 is 方法,而不会生成 get 方法
     */
    private boolean sellOut;
}

编译后的代码:

public class Product {
    private String name;
    private double price;
    private String description;
    private boolean sellOut;

    public Product() {
    }

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

    public double getPrice() {
        return this.price;
    }

    public String getDescription() {
        return this.description;
    }

    public boolean isSellOut() {
        return this.sellOut;
    }

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

    public void setPrice(double price) {
        this.price = price;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setSellOut(boolean sellOut) {
        this.sellOut = sellOut;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Product)) {
            return false;
        } else {
            Product other = (Product)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (Double.compare(this.getPrice(), other.getPrice()) != 0) {
                return false;
            } else if (this.isSellOut() != other.isSellOut()) {
                return false;
            } else {
                label40: {
                    Object this$name = this.getName();
                    Object other$name = other.getName();
                    if (this$name == null) {
                        if (other$name == null) {
                            break label40;
                        }
                    } else if (this$name.equals(other$name)) {
                        break label40;
                    }

                    return false;
                }

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

                return true;
            }
        }
    }

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

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        long $price = Double.doubleToLongBits(this.getPrice());
        result = result * 59 + (int)($price >>> 32 ^ $price);
        result = result * 59 + (this.isSellOut() ? 79 : 97);
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        Object $description = this.getDescription();
        result = result * 59 + ($description == null ? 43 : $description.hashCode());
        return result;
    }

    public String toString() {
        return "Product(name=" + this.getName() + ", price=" + this.getPrice() + ", description=" + this.getDescription() + ", sellOut=" + this.isSellOut() + ")";
    }

sellOut 字段是 Boolean 类型,没有生成它的 get 方法,生成了一个 isSellOut 方法。

名称不规则字段的 get set 方法名问题

import lombok.Data;

@Data
public class Book {
    private String isbn;
    private String title;
    private String aAuthor;
    private int pageCount;
    private double price;
}

编译后的代码:

public class Book {
    private String isbn;
    private String title;
    private String aAuthor;
    private int pageCount;
    private double price;

    // 省略无关代码
    public String getAAuthor() {
        return this.aAuthor;
    }

    public void setAAuthor(String aAuthor) {
        this.aAuthor = aAuthor;
    } 
}

使用 idea 生成的 get 和 set 方法却是:

public String getaAuthor() {
    return aAuthor;
}

public void setaAuthor(String aAuthor) {
    this.aAuthor = aAuthor;
}

因为这个原因,导致 lombok 和 mybatis 一起使用时有时就会产生问题。

生成的 equals 方法

使用 @Data 注解生成的 equals 方法,默认只判断了当前类的属性是否相等,而忽略了父类的属性,从而使两个明显不相等的对象通过 equals 判断为相等。
解决方式就是使用 @EnqualsAndHashCode 注解并显示指定 canSuper=true,这样就会调用父类的 equals 方法。

import lombok.Data;

/**
 * @author jxd
 * {@code @date} 2024/3/26 22:34
 */
@Data
public class PictureBook extends Book {
    private Integer pictureNm;
}

上面定义了一个 PictureBook 类,使用了 @Data 注解,如果调用 PictureBook 的 equals 方法,默认只会根据 pictureNm 来判断两个 PictureBook 对象是否相等。
需要添加如下的注解,才会调用父类的 equals 方法。

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值