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@Setterprivate 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@Setterprivate 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;@NonNullprivate 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 {@Testpublic 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 方法。