探究lombok-01
Java 8
org.springframework.boot 2.7.3
lombok 1.18.24
Eclipse Version: 2022-09 (4.25.0)
--
0、序
Project Lombok:
https://projectlombok.org/
经常用lombok,特别方便,已经离不开了,现在来深入了解下它。ben发布于博客园
为什么加一个(些)注解后,平平无奇的POJO就有这么多功能呢?
pom.xml 中和 lombok 相关的内容:
本文涉及的注解:ben发布于博客园
@Data、@Builder、@EqualsAndHashCode、@Slf4j
注,本文不涉及类继承。
一些博文说使用lombok存在问题,大家自行注意下:ben发布于博客园
1、测试代码
POJO:UserVO.java
import java.util.Date;
import java.util.List;
public class UserVO {
// 字段
private Integer id;
private String name;
private List<String> tags;
private Date createTime;
}
测试类:LombokMain.java
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Consumer;
public class LombokMain {
private static Consumer<Object> cs = System.out::println;
public static void main(String[] args) {
test(UserVO.class);
}
private static void test(Class cls) {
cs.accept("\n\n测试:class=" + cls);
Objects.requireNonNull(cls);
Class[] classes = cls.getDeclaredClasses();
prtClasses(classes);
cs.accept("----");
Constructor<?>[] constructors = cls.getDeclaredConstructors();
prtConstructors(constructors);
cs.accept("----");
Field[] fields = cls.getDeclaredFields();
prtFields(fields);
cs.accept("----");
Method[] methods = cls.getDeclaredMethods();
prtMethods(methods);
}
private static void prtClasses(Class[] classes) {
if (classes == null || classes.length == 0) {
cs.accept("prtClasses: length=0");
return;
}
cs.accept("prtClasses: length=" + classes.length);
for (Class el : classes) {
cs.accept("内部类: " + el.getCanonicalName() + ", " + el.getName()
+ ", " + el.getSimpleName() + ", " + el.getTypeName() + ", modifiers=" + el.getModifiers());
}
}
private static void prtConstructors(Constructor<?>[] constructors) {
if (constructors == null || constructors.length == 0) {
cs.accept("prtFields: length=0");
return;
}
cs.accept("prtConstructors: length=" + constructors.length);
for (Constructor el : constructors) {
cs.accept("构造方法名称:" + el.getName() + ", 参数数量:" + el.getParameterCount() + ", modifiers=" + el.getModifiers());
}
}
private static void prtFields(Field[] fields) {
if (fields == null || fields.length == 0) {
cs.accept("prtFields: length=0");
return;
}
cs.accept("prtFields: length=" + fields.length);
for (Field el : fields) {
cs.accept("字段:" + el.getName() + ", type=" + el.getType() + ", modifiers=" + el.getModifiers());
}
}
private static void prtMethods(Method[] methods) {
if (methods == null || methods.length == 0) {
cs.accept("prtMethods: length=0");
return;
}
cs.accept("prtMethods: length=" + methods.length);
for (Method el : methods) {
cs.accept("方法名称:" + el.getName() + ", 参数数量:" + el.getParameterCount() + ", modifiers=" + el.getModifiers());
}
}
}
注,UserVO.java 和 LombokMain.java 在同一个 package 中。ben发布于博客园
在 UserVO.java 没有使用 lombok 注解时,测试结果如下:
测试:class=class com.lib.webdemo.vo.UserVO
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO, 参数数量:0, modifiers=1
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=0
modifiers 是 什么意思呢?ben发布于博客园
Returns the Java language modifiers for this class or interface, encodedin an integer.
The modifiers consist of the Java Virtual Machine'sconstants for
public, protected, private, final, static, abstract and interface;
they should be decodedusing the methods of class Modifier.
具体值可以看 java.lang.reflect.Modifier 类。
modifiers=1 即 public修饰符;
modifiers=2 即 priavte修饰符。ben发布于博客园
可以相加,但本次测试没有这个情况。
2、@Data
给UserVO添加 @Data 注解,测试结果:
测试:class=class com.lib.webdemo.vo.UserVO
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO, 参数数量:0, modifiers=1
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=12
方法名称:equals, 参数数量:1, modifiers=1
方法名称:toString, 参数数量:0, modifiers=1
方法名称:hashCode, 参数数量:0, modifiers=1
方法名称:getName, 参数数量:0, modifiers=1
方法名称:getId, 参数数量:0, modifiers=1
方法名称:setName, 参数数量:1, modifiers=1
方法名称:getCreateTime, 参数数量:0, modifiers=1
方法名称:canEqual, 参数数量:1, modifiers=4
方法名称:setCreateTime, 参数数量:1, modifiers=1
方法名称:setId, 参数数量:1, modifiers=1
方法名称:getTags, 参数数量:0, modifiers=1
方法名称:setTags, 参数数量:1, modifiers=1
多了12个方法,除了setter、getter外,还有equals、hashCode、canEqual、toString。ben发布于博客园
@Data 是 使用频率最高的一个注解,一般用了它就不需要使用其它的了。它的效果相当于使用 @Getter、@Setter、@EqualsAndHashCode、@ToString 注解之和。
3、@EqualsAndHashCode
在 第1节 的基础上 添加 @EqualsAndHashCode,测试结果:
测试:class=class com.lib.webdemo.vo.UserVO
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO, 参数数量:0, modifiers=1
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=3
方法名称:equals, 参数数量:1, modifiers=1
方法名称:hashCode, 参数数量:0, modifiers=1
方法名称:canEqual, 参数数量:1, modifiers=4
多了3个方法:equals、hashCode、canEqual,其中,canEqual的modifiers=4(protected)ben发布于博客园。
4、@Builder
在 第1节 的基础上 添加 @Builder,测试结果:
测试:class=class com.lib.webdemo.vo.UserVO
prtClasses: length=1
内部类: com.lib.webdemo.vo.UserVO.UserVOBuilder, com.lib.webdemo.vo.UserVO$UserVOBuilder, UserVOBuilder, com.lib.webdemo.vo.UserVO$UserVOBuilder, modifiers=9
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO, 参数数量:4, modifiers=0
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=1
方法名称:builder, 参数数量:0, modifiers=9
可以看到,
多了一个 内部类 com.lib.webdemo.vo.UserVO.UserVOBuilder;ben发布于博客园
构造方法的 modifiers=0,即 不可以使用 new UserVO() 建立对象;
多了一个方法 builder,其 modifiers=9(public、static),用来生成 UserVOBuilder 对象,进而创建 UserVO 对象。
检查编译生成的class文件:ben发布于博客园
UserVO$UserVOBuilder.class // 内部类编译后
UserVO.class
那么,UserVOBuilder 的测试结果如何?
测试:class=class com.lib.webdemo.vo.UserVO$UserVOBuilder
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO$UserVOBuilder, 参数数量:0, modifiers=0
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=6
方法名称:name, 参数数量:1, modifiers=1
方法名称:toString, 参数数量:0, modifiers=1
方法名称:id, 参数数量:1, modifiers=1
方法名称:createTime, 参数数量:1, modifiers=1
方法名称:build, 参数数量:0, modifiers=1
方法名称:tags, 参数数量:1, modifiers=1
这里的 build方法 是用来创建 UserVO对象的。
生成UserVO对象:
前面提到无法使用 new UserVO() 创建对象,在使用 @Builder注解时,可以使用下面的方式创建对象:ben发布于博客园
// 链式编程
UserVO user = UserVO.builder()
.id(1)
.name("builder")
.tags(new ArrayList<String>())
.createTime(new Date())
.build();
注意,这里用到的 UserVO 的 builder方法、 UserVO$UserVOBuilder 的 build方法。
5、@Slf4j
在 第1节 的基础上 添加 @Slf4j,测试结果:
测试:class=class com.lib.webdemo.vo.UserVO
prtClasses: length=0
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO, 参数数量:0, modifiers=1
----
prtFields: length=5
字段:log, type=interface org.slf4j.Logger, modifiers=26
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=0
多了一个名为 log 的属性,用于 UserVO类 日志输出,其 modifiers=26(0x1A, final, static, private)ben发布于博客园。
6、注解组合
lombok的注解可以组合使用。ben发布于博客园
比如给第一节的UserVO添加下面三个注解:
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
@Builder
@Getter
@ToString
public class UserVO {
//...
}
测试结果:ben发布于博客园
测试:class=class com.lib.webdemo.vo.UserVO
prtClasses: length=1
内部类: com.lib.webdemo.vo.UserVO.UserVOBuilder, com.lib.webdemo.vo.UserVO$UserVOBuilder, UserVOBuilder, com.lib.webdemo.vo.UserVO$UserVOBuilder, modifiers=9
----
prtConstructors: length=1
构造方法名称:com.lib.webdemo.vo.UserVO, 参数数量:4, modifiers=0
----
prtFields: length=4
字段:id, type=class java.lang.Integer, modifiers=2
字段:name, type=class java.lang.String, modifiers=2
字段:tags, type=interface java.util.List, modifiers=2
字段:createTime, type=class java.util.Date, modifiers=2
----
prtMethods: length=6
方法名称:toString, 参数数量:0, modifiers=1
方法名称:getName, 参数数量:0, modifiers=1
方法名称:getId, 参数数量:0, modifiers=1
方法名称:getTags, 参数数量:0, modifiers=1
方法名称:builder, 参数数量:0, modifiers=9
方法名称:getCreateTime, 参数数量:0, modifiers=1
ben发布于博客园
~END.~
参考资料
1、
ben发布于博客园