文章目录
- 一、Lombok是什么
- 二、使用方法
- 1、引入Maven依赖
- 2、Idea中安装Lombok插件
- 三、常用注解
- @Setter
- @Getter
- @NoArgsConstructor
- @AllArgsConstructor
- @RequiredArgsConstructor
- @Builder
- @Data
- @Value
- @Slf4j
- @Cleanup
- @SneakyThrows
- @Synchronized
- @NonNull
- 四、Lombok的优点和缺点
- 五、参考文档
一、Lombok是什么
官网介绍如下:
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.
Lombok是一个Java类库,它提供了很多注解可以帮我们大大简化冗余代码,提升开发人员的开发效率。比如我们在写JavaBean时要给每个属性添加对应的 getter/setter、toString方法、构造器等一大堆代码,这些代码很冗长也没有什么技术含量,而且修改属性时还要去改对应的方法,浪费时间还容易出错。
Lombok可以通过添加注解的方法,在编译时自动为属性生成getter/setter、toString、构造器等代码,我们在源码中不再修改维护这一堆代码,只需添加注解即可,编译后的class文件中会自动生成。
二、使用方法
1、引入Maven依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
scope为provided,表明只在编译阶段生效,不打到包里,因为Lombok是在编译期生效,将带Lombok注解的Java文件编译为完整的Class文件。
2、Idea中安装Lombok插件
打开 File -> Settings -> Plugins,搜索 Lombok,点击 Installed 即可。
三、常用注解
对常用的注解进行说明,为了直观体现每个注解的效果,会列出注解在源码中的使用方式和编译后class文件中的实际效果
@Setter
注解在类上,为类中所有属性提供Setter方法;注解在某属性上,为该属性提供Setter方法。
源码
@Setter
public class UserInfo01 {
private String userId;
@Setter
private String userName;
@Setter
private Integer age;
}
实际效果
public class UserInfo01 {
private String userId;
private String userName;
private Integer age;
public UserInfo01() {
}
public void setUserId(final String userId) {
this.userId = userId;
}
public void setUserName(final String userName) {
this.userName = userName;
}
public void setAge(final Integer age) {
this.age = age;
}
}
@Getter
注解在类上,为类中所有属性提供Getter方法;注解在某属性上,为该属性提供Getter方法。
源码
@Getter
public class UserInfo02 {
private String userId;
@Setter
private String userName;
@Setter
private Integer age;
}
@NoArgsConstructor
注解在类上,为类提供一个无参的构造方法。类中有 final 字段没有被初始化时,编译器会报错,此时可用 @NoArgsConstructor(force = true),然会为没有初始化的 final 字段设置默认值。
源码
@NoArgsConstructor(force = true)
public class UserInfo03 {
private final String userId;
private String userName;
private Integer age;
}
实际效果
public class UserInfo03 {
private final String userId = null;
private String userName;
private Integer age;
public UserInfo03() {
}
}
@AllArgsConstructor
注解在类上,为类提供一个全参的构造方法。
源码
@AllArgsConstructor
public class UserInfo04 {
private String userId;
private String userName;
private Integer age;
}
实际效果
public class UserInfo04 {
private String userId;
private String userName;
private Integer age;
public UserInfo04(final String userId, final String userName, final Integer age) {
this.userId = userId;
this.userName = userName;
this.age = age;
}
}
@RequiredArgsConstructor
注解在类上,为未初始化的final属性提供一个private的构造方法;可通过staticName参数生成一个static方法。
源码
@RequiredArgsConstructor(staticName = "of")
public class UserInfo05 {
private final String userId;
private final String userName = "张三";
private Integer age;
}
实际效果
public class UserInfo05 {
private final String userId;
private final String userName = "张三";
private Integer age;
private UserInfo05(final String userId) {
this.userId = userId;
}
public static UserInfo05 of(final String userId) {
return new UserInfo05(userId);
}
}
@Builder
注解在类上,建造者模式的一个变种,在创建复杂对象时常使用。
源码
@Builder
public class UserInfo06 {
private final String userId;
private final String userName;
private Integer age;
}
实际效果
public class UserInfo06 {
private final String userId;
private final String userName;
private Integer age;
UserInfo06(final String userId, final String userName, final Integer age) {
this.userId = userId;
this.userName = userName;
this.age = age;
}
public static UserInfo06.UserInfo06Builder builder() {
return new UserInfo06.UserInfo06Builder();
}
public static class UserInfo06Builder {
private String userId;
private String userName;
private Integer age;
UserInfo06Builder() {
}
public UserInfo06.UserInfo06Builder userId(final String userId) {
this.userId = userId;
return this;
}
public UserInfo06.UserInfo06Builder userName(final String userName) {
this.userName = userName;
return this;
}
public UserInfo06.UserInfo06Builder age(final Integer age) {
this.age = age;
return this;
}
public UserInfo06 build() {
return new UserInfo06(this.userId, this.userName, this.age);
}
public String toString() {
return "UserInfo06.UserInfo06Builder(userId=" + this.userId + ", userName=" + this.userName + ", age=" + this.age + ")";
}
}
}
使用Builder模式创建对象
public class BuilderTest {
public static void main(String[] args) {
// Builder模式创建对象
UserInfo06 userInfo06 = UserInfo06.builder().userId("1").userName("张三").age(99).build();
}
}
@Data
注解在类上,是@Getter、@Setter、@ToString、@EqualsAndHashCode、 @RequiredArgsConstructor的集合。
源码
@Data
public class UserInfo07 {
private String userId;
private String userName;
private Integer age;
}
实际效果
public class UserInfo07 {
private String userId;
private String userName;
private Integer age;
public UserInfo07() {
}
public String getUserId() {
return this.userId;
}
public String getUserName() {
return this.userName;
}
public Integer getAge() {
return this.age;
}
public void setUserId(final String userId) {
this.userId = userId;
}
public void setUserName(final String userName) {
this.userName = userName;
}
public void setAge(final Integer age) {
this.age = age;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof UserInfo07)) {
return false;
} else {
UserInfo07 other = (UserInfo07)o;
if (!other.canEqual(this)) {
return false;
} else {
label47: {
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age == null) {
break label47;
}
} else if (this$age.equals(other$age)) {
break label47;
}
return false;
}
Object this$userId = this.getUserId();
Object other$userId = other.getUserId();
if (this$userId == null) {
if (other$userId != null) {
return false;
}
} else if (!this$userId.equals(other$userId)) {
return false;
}
Object this$userName = this.getUserName();
Object other$userName = other.getUserName();
if (this$userName == null) {
if (other$userName != null) {
return false;
}
} else if (!this$userName.equals(other$userName)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof UserInfo07;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $age = this.getAge();
int result = result * 59 + ($age == null ? 43 : $age.hashCode());
Object $userId = this.getUserId();
result = result * 59 + ($userId == null ? 43 : $userId.hashCode());
Object $userName = this.getUserName();
result = result * 59 + ($userName == null ? 43 : $userName.hashCode());
return result;
}
public String toString() {
return "UserInfo07(userId=" + this.getUserId() + ", userName=" + this.getUserName() + ", age=" + this.getAge() + ")";
}
}
@Value
注解在类上,和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,也不会生成set方法。
源码
@Value
public class UserInfo08 {
private String userId;
private String userName;
private Integer age;
}
实际效果
public final class UserInfo08 {
private final String userId;
private final String userName;
private final Integer age;
public UserInfo08(final String userId, final String userName, final Integer age) {
this.userId = userId;
this.userName = userName;
this.age = age;
}
public String getUserId() {
return this.userId;
}
public String getUserName() {
return this.userName;
}
public Integer getAge() {
return this.age;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof UserInfo08)) {
return false;
} else {
UserInfo08 other;
label44: {
other = (UserInfo08)o;
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age == null) {
break label44;
}
} else if (this$age.equals(other$age)) {
break label44;
}
return false;
}
Object this$userId = this.getUserId();
Object other$userId = other.getUserId();
if (this$userId == null) {
if (other$userId != null) {
return false;
}
} else if (!this$userId.equals(other$userId)) {
return false;
}
Object this$userName = this.getUserName();
Object other$userName = other.getUserName();
if (this$userName == null) {
if (other$userName != null) {
return false;
}
} else if (!this$userName.equals(other$userName)) {
return false;
}
return true;
}
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $age = this.getAge();
int result = result * 59 + ($age == null ? 43 : $age.hashCode());
Object $userId = this.getUserId();
result = result * 59 + ($userId == null ? 43 : $userId.hashCode());
Object $userName = this.getUserName();
result = result * 59 + ($userName == null ? 43 : $userName.hashCode());
return result;
}
public String toString() {
return "UserInfo08(userId=" + this.getUserId() + ", userName=" + this.getUserName() + ", age=" + this.getAge() + ")";
}
}
@Slf4j
注解在类上;为类提供一个 属性名为 log 的日志对象。
源码
@Slf4j
public class Slf4jTest {
public static void main(String[] args) {
log.info("日志打印测试");
}
}
实际效果
public class Slf4jTest {
private static final Logger log = LoggerFactory.getLogger(Slf4jTest.class);
public Slf4jTest() {
}
public static void main(String[] args) {
log.info("日志打印测试");
}
}
@Cleanup
注解在流上,生成关闭流的方法。
源码
public class CleanupTest {
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) {
break;
}
out.write(b, 0, r);
}
}
}
实际效果
public class CleanupTest {
public CleanupTest() {
}
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream(args[0]);
try {
FileOutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while(true) {
int r = in.read(b);
if (r == -1) {
return;
}
out.write(b, 0, r);
}
} finally {
if (Collections.singletonList(out).get(0) != null) {
out.close();
}
}
} finally {
if (Collections.singletonList(in).get(0) != null) {
in.close();
}
}
}
}
@SneakyThrows
注解在方法上,给方法中的代码添加try/catch捕获异常。
源码
public class SneakyThrowsTest {
@SneakyThrows
public void test() {
System.out.println("test");
}
}
实际效果
public class SneakyThrowsTest {
public SneakyThrowsTest() {
}
public void test() {
try {
System.out.println("test");
} catch (Throwable var2) {
throw var2;
}
}
}
@Synchronized
注解在方法上,给方法中的代码添加同步锁。
源码
public class SynchronizedTest {
@Synchronized
public void test() {
System.out.println("test");
}
}
实际效果
public class SynchronizedTest {
private final Object $lock = new Object[0];
public SynchronizedTest() {
}
public void test() {
synchronized(this.$lock) {
System.out.println("test");
}
}
}
@NonNull
注解在参数上,在方法或构造函数的参数上使用@NonNull会给参数生成null-check语句。
public class NonNullTest {
public static void main(String[] args) {
test(null);
}
public static void test(@NonNull String id) {
System.out.println(id);
}
}
实际效果
public class NonNullTest {
public NonNullTest() {
}
public static void main(String[] args) {
test((String) null);
}
public static void test(@NonNull String id) {
if (id == null) {
throw new NullPointerException("id is marked non-null but is null");
} else {
System.out.println(id);
}
}
}
四、Lombok的优点和缺点
Lombok当然不是万能的,使用Lombok能给开发人员提供很大的便利,同时也会带来一些问题,其优缺点如下。
优点:
- 简化了大量的冗余代码,注解代替getter/setter等方法,能让源码更简洁;
- 减少了代码维护 难度,修改属性后,上述方法也会随之改变,防止忘改错该问题;
- 提升了开发效率,减少重复劳动。
缺点:
- 使用Lombok需要在Idea中安装插件,团队里一个人用了Lombok其它人也得跟着用;
- Lombok很多方法是自动生成的,屏蔽了代码的内部逻辑,一定程度上降低了代码的可读性;
- 对Lombok理解较少的话会出现意想不到的现象,比如使用@Data注解时, 会自动生成equals()方法,但是这个equals()方法只会比较子类的属性,不会考虑从父类继承的属性,要想比较父类方法需添加@EqualsAndHashCode(callSuper=true)注解。
Lombok有优点也有缺点,个人认为瑕不掩瑜,还是比较好用的,大家根据自己情况按需使用。