参考资料
- 最全的 lombok 注解详情(随着版本不定时更新)
- @Accessors 注解极简教程
- Lombok工具 : 常用注解介绍 (全)
- Lombok Experimental features
- Lombok注解之@With
- @FieldNameConstants(自动生成字段名称常量)
- 【Lombok】@FieldNameConstants | 为你的字段生成一个以字段名称为值的常量
目录
一. @Accessors
- 可以同时作用于类和属性上,属性上的优先级 > 类上的优先级
1.1 fluent 属性
- 默认值为false
- 当为 true 时,对应字段的 getter 方法前面就没有 get,setter 方法就不会有 set
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
public class Student {
private String personId;
private String personName;
private String age;
private String address;
public static void main(String[] args) {
Student student = new Student();
// 不需要set
student.age("1");
student.address("地球");
// 不需要get
student.personId();
student.personName();
}
}
1.2 chain 属性
- 默认值为false
- 当为 true 时,对应字段的 setter 方法调用后,会返回当前对象
import lombok.Data;
import lombok.experimental.Accessors;
@Data
// 作用于类上,表示所有的属性都可以链式调用
@Accessors(chain = true)
public class Student {
private String personId;
private String personName;
// 作用于属性上,表示这个属性不链式调用
@Accessors(chain = false)
private String age;
private String address;
public static void main(String[] args) {
Student student = new Student();
student.setPersonId("1")
.setPersonName("贾飞天")
// age属性并不链式调用,所以不会返回对象本身
.setAge("10");
}
}
1.3 prefix 属性
- 该属性是一个字符串数组
- 当该数组有值时,表示忽略字段中对应的前缀,生成对应的 getter 和 setter 方法。
import lombok.Data;
import lombok.experimental.Accessors;
@Data
// 忽略属性前缀person和human,并且链式调用
@Accessors(prefix = {"person", "human"}, chain = true)
public class Student {
private String personId;
private String humanName;
private String age;
private String address;
public static void main(String[] args) {
Student student = new Student();
// 前缀person和human被忽略
student.setId("1")
.setName("贾飞天")
.setAge("18")
.setAddress("地球");
}
}
二. @Builder
- 通过建造者模式创建对象
- 会生成一个全参的构造函数,如果我们使用无参构造函数的话就会报错
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Student {
private String personId;
private String humanName;
private String age;
// 非 final 的字段可以有默认值
@Builder.Default
private String address = "地球";
public static void main(String[] args) {
Student student = Student.builder()
.personId("1")
.humanName("贾飞天")
.age("10")
// 没有创建address属性
.build();
System.out.println(student);
/*
因为我们使用@Builder.Default给address指定了默认值
Student(personId=1, humanName=贾飞天, age=10, address=地球)
*/
}
}
三. @Singular
- 该注解需要配合
@Builder注解
使用,用于注解一个集合字段 - 如果没有指定value值的话,那么集合字段名需要是复数形式
- 如果指定了value值,集合字段名就是我们指定的value值
- 会生成添加元素方法向集合添加单个元素
import lombok.Builder;
import lombok.Data;
import lombok.Singular;
import java.util.List;
@Builder
@Data
public class Student {
private String personId;
private String humanName;
private String age;
/**
* 属性名结尾不为 s ,
* 因此必须在@Singular注解中手动指定构建时使用的名称
*/
@Singular("address")
private List<String> addressList;
/**
* 属性名结尾为 s,
* 因此可以不手动指定构建时使用的名称,该名称为去掉s之后的属性名
*/
@Singular
private List<String> hobbys;
public static void main(String[] args) {
Student student = Student.builder()
.personId("110")
.humanName("贾飞天")
// 可以一个一个向集合中添加元素,无需创建一个集合
.address("地球").address("火星")
// 也可以直接添加集合
.addressList(Arrays.asList("宇宙", "银河系"))
// 因为hobbys这个属性名以s结尾,所以添加单个元素的时候,用去掉s的属性名即可
.hobby("吃饭").hobby("睡觉")
.hobbys(Arrays.asList("学习java", "学习Python"))
.build();
System.out.println(student);
/**
Student(
personId=110
, humanName=贾飞天
, age=null
, addressList=[地球, 火星, 宇宙, 银河系]
, hobbys=[吃饭, 睡觉, 学习java, 学习Python]
)
*/
}
}
四. @Cleanup
- 作用于局部变量,可以自动关闭资源
- 仅针对实现了
java.io.Closeable
接口的对象有效
import lombok.Cleanup;
import java.io.File;
import java.io.FileInputStream;
public static void main(String[] args) throws IOException {
@Cleanup FileInputStream inputStream = new FileInputStream(new File("D:\\test\\application.yml"));
byte[] bytes = inputStream.readAllBytes();
System.out.println(Arrays.toString(bytes));
}
👉编译后
五. @RequiredArgsConstructor
⏹具体使用请参考这篇博客
SpringBoot 使用lombok的@RequiredArgsConstructor注解进行Bean注入
六. @ExtensionMethod
- 作用于类,向类中添加方法。
- 要添加的方法的修饰符必须是 public,必须是静态方法,方法必须要有对应的参数,变量必须初始化。
⏹定义一个工具类
public class StringExtension {
// 判断字符串是否为null或者空字符串
public static boolean isNullOrEmpty(String str) {
if (str == null || str.equals("")) {
return true;
}
return false;
}
// 判断不是null或空字符串
public static boolean isNotNullOrEmpty(String str) {
return !isNullOrEmpty(str);
}
}
⏹使用👇
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;
import lombok.experimental.ExtensionMethod;
@Service
// 将StringExtension类添加到当前类中
@ExtensionMethod({ StringExtension.class })
public class Test implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 需要做判断的值
String value = null;
// 😅使用@ExtensionMethod注解之前的常规写法
boolean valueResult1 = StringExtension.isNullOrEmpty(value);
System.out.println(valueResult1); // true
/**
* 💪使用@ExtensionMethod注解之后,
* StringExtension类中的方法默认添加到当前类中,
* 虽然value的值为null,但是在编译的时候会进行处理,处理为常规写法这种形式
*/
boolean valueResult2 = value.isNullOrEmpty();
System.out.println(valueResult2); // true
}
}
7. @UtilityClass
- 将普通类转换为工具类
- 被该注解作用的类无法实例化,并且该类会添加
final
- 该类中的属性和方法都会被添加
static
⏹被@UtilityClass
注解作用的类
import lombok.experimental.UtilityClass;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@UtilityClass
public class Base64Utils {
private final Base64.Encoder encoder = Base64.getEncoder();
private final Base64.Decoder decoder = Base64.getDecoder();
// 加密
public String encode(String text) {
return encoder.encodeToString(text.getBytes(StandardCharsets.UTF_8));
}
// 解密
public String decode(String encodedText) {
return new String(decoder.decode(encodedText), StandardCharsets.UTF_8);
}
}
⏹编译完成之后
private Base64Utils() { }
构造方法是lombok自动生成的。
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
public final class Base64Utils {
private static final Encoder encoder = Base64.getEncoder();
private static final Decoder decoder = Base64.getDecoder();
public static String encode(String text) {
return encoder.encodeToString(text.getBytes(StandardCharsets.UTF_8));
}
public static String decode(String encodedText) {
return new String(decoder.decode(encodedText), StandardCharsets.UTF_8);
}
private Base64Utils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}
八. @FieldDefaults
⏹用来指定类和属性的访问修饰符,也可以用来添加final
8.1 level
- 用来指定属性的修饰符,可指定为
- PUBLIC
- MODULE
- PROTECTED
- PACKAGE
- PRIVATE
- 如果属性上本身就存在修饰符的话,使用属性上自带的修饰符
- 只作用于属性,不作用于方法上
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ZTestEntity {
// 手动指定了修饰符
public String id;
protected String address;
// 没有指定修饰符
String name;
Boolean isAdmin;
// 只作用于属性,不作用于方法上
String getData() {
return "";
}
}
⏹编译之后的效果
public class ZTestEntity {
public String id;
protected String address;
private String name;
private Boolean isAdmin;
public ZTestEntity() {
}
String getData() {
return "";
}
}
8.2 makeFinal
- 用来将属性指定为
final
- 指定的范围是类上的所有属性,不想被指定final的属性,使用
@NonFinal
注解来修饰
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
@FieldDefaults(level = AccessLevel.PUBLIC, makeFinal = true)
public class ZTestEntity {
// 使用@NonFinal注解,避免被final化
@NonFinal
public String id = "";
protected String address = "";
// 没有指定修饰符
@NonFinal
String name = "";
Boolean isAdmin = true;
}
⏹编译之后的效果
public class ZTestEntity {
public String id = "";
protected final String address = "";
public String name = "";
public final Boolean isAdmin = true;
public ZTestEntity() {
}
}
九. @FieldNameConstants
- 作用于类上,用于为属性生成一个常量,常量值和属性名相同
import lombok.experimental.FieldNameConstants;
@FieldNameConstants
public class Test34Entity {
private String id;
private String name;
private String content;
}
- 编译后
public class Test34Entity {
private String id;
private String name;
private String content;
public Test34Entity() {
}
public static final class Fields {
public static final String content = "content";
public static final String name = "name";
public static final String id = "id";
public Fields() {
}
}
}
- 使用
public static void main(String[] args) {
// 得到属性名所对应的属性值
String id = Test34Entity.Fields.id;
System.out.println(id); // id
String content = Test34Entity.Fields.content;
System.out.println(content); // content
}
9.1 asEnum 生成枚举类
- 配置
asEnum = true
import lombok.experimental.FieldNameConstants;
@FieldNameConstants(asEnum = true)
public class Test34Entity {
private String id;
private String name;
private String content;
}
- 编译后,在类的内部生成了枚举类
public class Test34Entity {
private String id;
private String name;
private String content;
public Test34Entity() {
}
public static enum Fields {
id,
name,
content;
private Fields() {
}
}
}
9.2 innerTypeName 指定内部类名称
- 配置
innerTypeName = "名称"
import lombok.experimental.FieldNameConstants;
@FieldNameConstants(innerTypeName = "Fyh")
public class Test34Entity {
private String id;
private String name;
private String content;
}
- 编译后
public class Test34Entity {
private String id;
private String name;
private String content;
public Test34Entity() {
}
public static final class Fyh {
public static final String content = "content";
public static final String name = "name";
public static final String id = "id";
public Fyh() {
}
}
}
9.3 onlyExplicitlyIncluded 只引入指定字段
onlyExplicitlyIncluded = true
+@FieldNameConstants.Include
指定需要生成的字段@FieldNameConstants.Exclude
:用来排除指定字段
import lombok.experimental.FieldNameConstants;
@FieldNameConstants(onlyExplicitlyIncluded = true)
public class Test34Entity {
@FieldNameConstants.Include
private String id;
private String name;
private String content;
}
- 编译后
public class Test34Entity {
private String id;
private String name;
private String content;
public Test34Entity() {
}
public static final class Fields {
public static final String id = "id";
public Fields() {
}
}
}
十. @With
- 作用于类或类中的属性,生成多个
with + 变量名
的方法,返回当前对象的副本(新对象) - 需要有全参数的构造方法,配合
@AllArgsConstructor
注解使用
import lombok.*;
// value = AccessLevel.PROTECTED 指定生成的with方法的修饰符
@With(value = AccessLevel.PROTECTED)
@AllArgsConstructor
@ToString
public class ZTestEntity {
private String id;
private String address;
}
⏹编译之后的效果
- 在
withId()
和withAddress()
方法上可以看到如果指定了新的属性值的话,返回的是新的对象 - 由于
@With(value = AccessLevel.PROTECTED)
指定了PROTECTED
,因此生成的with方法也是protected
的修饰符
public class ZTestEntity {
private String id;
private String address;
protected ZTestEntity withId(String id) {
return this.id == id ? this : new ZTestEntity(id, this.address);
}
protected ZTestEntity withAddress(String address) {
return this.address == address ? this : new ZTestEntity(this.id, address);
}
public ZTestEntity(String id, String address) {
this.id = id;
this.address = address;
}
public String toString() {
return "ZTestEntity(id=" + this.id + ", address=" + this.address + ")";
}
}
⏹使用with方法构造新对象
// 通过构造方法构造一个对象
ZTestEntity entity = new ZTestEntity("1", "地球");
System.out.println(entity); // ZTestEntity(id=1, address=地球)
// 通过@With注解生成的with方法构造的是原对象的副本,只需改动属性,就可以生成新的对象
ZTestEntity entity1 = entity.withId("2");
System.out.println(entity1); // ZTestEntity(id=2, address=地球)
ZTestEntity entity2 = entity.withAddress("月球");
System.out.println(entity2); // ZTestEntity(id=1, address=月球)