随着编程以及各种框架的发展,大大提供了开发的简洁和便利性。在开发过程中,我们经常要定义各种Bean,在Bean中会出现大量的getter、setter方法,有时还会重写toString等方法,比如:
/**
* @author javaerui
* @Description:
* @date 2021/1/22
*/
public class User {
public User() {
}
public User(String name, long id, Integer age, boolean vip, Boolean svip) {
this.name = name;
this.id = id;
this.age = age;
this.vip = vip;
this.svip = svip;
}
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean isVip() {
return vip;
}
public void setVip(boolean vip) {
this.vip = vip;
}
public Boolean getSvip() {
return svip;
}
public void setSvip(Boolean svip) {
this.svip = svip;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
", vip=" + vip +
", svip=" + svip +
'}';
}
}
大量的方法重置着整个类,让这个类看上去失去了很多美观性。于是,Lombok诞生了,我们只需要编写Bean的属性,然后使用Lombok提供的注解便能够完成getter、setter等方法的添加。对于JVM来说,它是只能够识别class字节码的,而我们程序员一般编写的java源码需要先编译成class字节码才能够被JVM识别并运行,所以Lombok是对class字节码做了文章,在.java文件的源码级别使用Lombok提供的注解,Lombok会在类编译成.class字节码的时候根据特定注解对类添加特定的方法,比如:
/**
* @author javaerui
* @Description:
* @date 2021/1/22
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译User.java后,用IDEA打开编译生成的User.class内容:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User() {
}
public User(String name, long id, Integer age, boolean vip, Boolean svip) {
this.name = name;
this.id = id;
this.age = age;
this.vip = vip;
this.svip = svip;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean isVip() {
return this.vip;
}
public void setVip(boolean vip) {
this.vip = vip;
}
public Boolean getSvip() {
return this.svip;
}
public void setSvip(Boolean svip) {
this.svip = svip;
}
public String toString() {
return "User{name='" + this.name + '\'' + ", id=" + this.id + ", age=" + this.age + ", vip=" + this.vip + ", svip=" + this.svip + '}';
}
}
对User类使用了Lombok提供的注解后,类的内容实质上和上面没有使用Lombok的效果是一样的。从源码层对比两个类,使用Lombok注解后,看上去更加简洁明了了。
█ 简单使用
(1)IDEA安装Lombok插件:
(2)引入依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
(3)以User类为例,查看Lombok提供的注解所对应的方法。
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
- @Getter
对Bean的属性构建标准getter方法。
源码:
@Getter
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User() {
}
public String getName() {
return this.name;
}
public long getId() {
return this.id;
}
public Integer getAge() {
return this.age;
}
public boolean isVip() {
return this.vip;
}
public Boolean getSvip() {
return this.svip;
}
}
- @Setter
对属性构建set方法。
源码:
@Setter
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User() {
}
public void setName(String name) {
this.name = name;
}
public void setId(long id) {
this.id = id;
}
public void setAge(Integer age) {
this.age = age;
}
public void setVip(boolean vip) {
this.vip = vip;
}
public void setSvip(Boolean svip) {
this.svip = svip;
}
}
- @ToString
重写toString方法。
源码:
@ToString
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User() {
}
public String toString() {
return "User(name=" + this.name + ", id=" + this.id + ", age=" + this.age + ", vip=" + this.vip + ", svip=" + this.svip + ")";
}
}
- @EqualsAndHashCode
重写equals与hashcode方法。
源码:
@EqualsAndHashCode
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后,从下面的方法可以看出,Lombok重写的方法会比较所有属性:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User() {
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else if (this.id != other.id) {
return false;
} else if (this.vip != other.vip) {
return false;
} else {
label52: {
Object this$age = this.age;
Object other$age = other.age;
if (this$age == null) {
if (other$age == null) {
break label52;
}
} else if (this$age.equals(other$age)) {
break label52;
}
return false;
}
Object this$svip = this.svip;
Object other$svip = other.svip;
if (this$svip == null) {
if (other$svip != null) {
return false;
}
} else if (!this$svip.equals(other$svip)) {
return false;
}
Object this$name = this.name;
Object other$name = other.name;
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
long $id = this.id;
int result = result * 59 + (int)($id >>> 32 ^ $id);
result = result * 59 + (this.vip ? 79 : 97);
Object $age = this.age;
result = result * 59 + ($age == null ? 43 : $age.hashCode());
Object $svip = this.svip;
result = result * 59 + ($svip == null ? 43 : $svip.hashCode());
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
}
- @AllArgsConstructor、@NoArgsConstructor
@AllArgsConstructor构建全参构造器,@NoArgsConstructor构建无参构造器。
源码:
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User(String name, long id, Integer age, boolean vip, Boolean svip) {
this.name = name;
this.id = id;
this.age = age;
this.vip = vip;
this.svip = svip;
}
public User() {
}
}
- @Builder
对Bean构建Builder构建者模式。
源码:
@Builder
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
User(String name, long id, Integer age, boolean vip, Boolean svip) {
this.name = name;
this.id = id;
this.age = age;
this.vip = vip;
this.svip = svip;
}
public static User.UserBuilder builder() {
return new User.UserBuilder();
}
public static class UserBuilder {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
UserBuilder() {
}
public User.UserBuilder name(String name) {
this.name = name;
return this;
}
public User.UserBuilder id(long id) {
this.id = id;
return this;
}
public User.UserBuilder age(Integer age) {
this.age = age;
return this;
}
public User.UserBuilder vip(boolean vip) {
this.vip = vip;
return this;
}
public User.UserBuilder svip(Boolean svip) {
this.svip = svip;
return this;
}
public User build() {
return new User(this.name, this.id, this.age, this.vip, this.svip);
}
public String toString() {
return "User.UserBuilder(name=" + this.name + ", id=" + this.id + ", age=" + this.age + ", vip=" + this.vip + ", svip=" + this.svip + ")";
}
}
}
- @Cleanup
用于局部变量,会调用变量的close方法来关闭资源。@Cleanup标记的局部变量,必须具有close方法。
源码:
public void method() throws IOException {
@Cleanup FileOutputStream fileOutputStream = new FileOutputStream("E:\\Downloads\\java.txt");
fileOutputStream.write("Hello World".getBytes());
}
编译后:
public void method() throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("E:\\Downloads\\java.txt");
try {
fileOutputStream.write("Hello World".getBytes());
} finally {
if (Collections.singletonList(fileOutputStream).get(0) != null) {
fileOutputStream.close();
}
}
}
- @NonNull
非空检查,当设置的值为空时,会抛异常。
public void setName(@NonNull String name) {
this.name = name;
}
调用,对name进行赋值为null:
User user = new User();
user.setName(null);
抛异常:
- @RequiredArgsConstructor
对标记了@NonNull的属性构建有参构造器。
源码:
@RequiredArgsConstructor
public class User {
@NonNull
private String name;
private long id;
private Integer age;
@NonNull
private boolean vip;
private Boolean svip;
}
编译后,从这里可以看出@NonNull标注的字段会加非空判断:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import lombok.NonNull;
public class User {
@NonNull
private String name;
private long id;
private Integer age;
@NonNull
private boolean vip;
private Boolean svip;
public User(@NonNull String name, @NonNull boolean vip) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
this.name = name;
this.vip = vip;
}
}
}
- @Data
作用是@Getter、@Setter、@ToString、@EqualsAndHashCode、@RequiredArgsConstructor的聚合。
源码:
@Data
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.util.List;
import lombok.NonNull;
public class User {
@NonNull
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
private List<String> list;
public User(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
this.name = name;
}
}
@NonNull
public String getName() {
return this.name;
}
public long getId() {
return this.id;
}
public Integer getAge() {
return this.age;
}
public boolean isVip() {
return this.vip;
}
public Boolean getSvip() {
return this.svip;
}
public List<String> getList() {
return this.list;
}
public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
this.name = name;
}
}
public void setId(long id) {
this.id = id;
}
public void setAge(Integer age) {
this.age = age;
}
public void setVip(boolean vip) {
this.vip = vip;
}
public void setSvip(Boolean svip) {
this.svip = svip;
}
public void setList(List<String> list) {
this.list = list;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else if (this.getId() != other.getId()) {
return false;
} else if (this.isVip() != other.isVip()) {
return false;
} else {
label64: {
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age == null) {
break label64;
}
} else if (this$age.equals(other$age)) {
break label64;
}
return false;
}
label57: {
Object this$svip = this.getSvip();
Object other$svip = other.getSvip();
if (this$svip == null) {
if (other$svip == null) {
break label57;
}
} else if (this$svip.equals(other$svip)) {
break label57;
}
return false;
}
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
Object this$list = this.getList();
Object other$list = other.getList();
if (this$list == null) {
if (other$list != null) {
return false;
}
} else if (!this$list.equals(other$list)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
long $id = this.getId();
int result = result * 59 + (int)($id >>> 32 ^ $id);
result = result * 59 + (this.isVip() ? 79 : 97);
Object $age = this.getAge();
result = result * 59 + ($age == null ? 43 : $age.hashCode());
Object $svip = this.getSvip();
result = result * 59 + ($svip == null ? 43 : $svip.hashCode());
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $list = this.getList();
result = result * 59 + ($list == null ? 43 : $list.hashCode());
return result;
}
public String toString() {
return "User(name=" + this.getName() + ", id=" + this.getId() + ", age=" + this.getAge() + ", vip=" + this.isVip() + ", svip=" + this.getSvip() + ", list=" + this.getList() + ")";
}
}
- @SneakyThrows
标记方法抛出的异常。
源码:
@SneakyThrows(IOException.class)
public void method() {
FileOutputStream fileOutputStream = new FileOutputStream("E:\\Downloads\\java.txt");
fileOutputStream.write("Hello World".getBytes());
}
编译后:
public void method() {
try {
FileOutputStream fileOutputStream = new FileOutputStream("E:\\Downloads\\java.txt");
fileOutputStream.write("Hello World".getBytes());
} catch (IOException var2) {
throw var2;
}
}
- @Synchronized
对方法体进行同步操作。
源码:
@Synchronized
public void method() throws IOException{
FileOutputStream fileOutputStream = new FileOutputStream("E:\\Downloads\\java.txt");
fileOutputStream.write("Hello World".getBytes());
}
编译后:
private final Object $lock = new Object[0];
public void method() throws IOException {
synchronized(this.$lock) {
FileOutputStream fileOutputStream = new FileOutputStream("E:\\Downloads\\java.txt");
fileOutputStream.write("Hello World".getBytes());
}
}
- @Value
构建一个final修饰的类,并提供全参构造器,getter方法,重新equals、hashcode、toString方法。
源码:
@Value
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public final class User {
private final String name;
private final long id;
private final Integer age;
private final boolean vip;
private final Boolean svip;
public User(String name, long id, Integer age, boolean vip, Boolean svip) {
this.name = name;
this.id = id;
this.age = age;
this.vip = vip;
this.svip = svip;
}
public String getName() {
return this.name;
}
public long getId() {
return this.id;
}
public Integer getAge() {
return this.age;
}
public boolean isVip() {
return this.vip;
}
public Boolean getSvip() {
return this.svip;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (this.getId() != other.getId()) {
return false;
} else if (this.isVip() != other.isVip()) {
return false;
} else {
label49: {
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age == null) {
break label49;
}
} else if (this$age.equals(other$age)) {
break label49;
}
return false;
}
Object this$svip = this.getSvip();
Object other$svip = other.getSvip();
if (this$svip == null) {
if (other$svip != null) {
return false;
}
} else if (!this$svip.equals(other$svip)) {
return false;
}
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
return true;
}
}
}
public int hashCode() {
int PRIME = true;
int result = 1;
long $id = this.getId();
int result = result * 59 + (int)($id >>> 32 ^ $id);
result = result * 59 + (this.isVip() ? 79 : 97);
Object $age = this.getAge();
result = result * 59 + ($age == null ? 43 : $age.hashCode());
Object $svip = this.getSvip();
result = result * 59 + ($svip == null ? 43 : $svip.hashCode());
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
public String toString() {
return "User(name=" + this.getName() + ", id=" + this.getId() + ", age=" + this.getAge() + ", vip=" + this.isVip() + ", svip=" + this.getSvip() + ")";
}
}
- @With
构建一个withXX的方法,实现将参数比较,如果是相等,返回当前对象,如果不等,创建新的对象。@With标记的类必须提供一个全参构造器,否则无法编译通过(为什么呢?看完编译后的源码就清楚了)。
源码:
@AllArgsConstructor
@With
public class User {
private String name;
public User(String name) {
this.name = name;
}
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
}
编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class User {
private String name;
private long id;
private Integer age;
private boolean vip;
private Boolean svip;
public User(String name) {
this.name = name;
}
public User(String name, long id, Integer age, boolean vip, Boolean svip) {
this.name = name;
this.id = id;
this.age = age;
this.vip = vip;
this.svip = svip;
}
public User withName(String name) {
// 通过new User的全参构造器创建对象的,所以必须提供一个全参构造器
return this.name == name ? this : new User(name, this.id, this.age, this.vip, this.svip);
}
public User withId(long id) {
return this.id == id ? this : new User(this.name, id, this.age, this.vip, this.svip);
}
public User withAge(Integer age) {
return this.age == age ? this : new User(this.name, this.id, age, this.vip, this.svip);
}
public User withVip(boolean vip) {
return this.vip == vip ? this : new User(this.name, this.id, this.age, vip, this.svip);
}
public User withSvip(Boolean svip) {
return this.svip == svip ? this : new User(this.name, this.id, this.age, this.vip, svip);
}
}
- var、val
声明局部变量。
源码:
public void method() {
var x = 10;
val y = 1.1;
var list = new ArrayList<>();
list.add("hello world");
}
编译后:
public void method() {
int x = true;
double y = 1.1D;
ArrayList<Object> list = new ArrayList();
list.add("hello world");
}
- @CommonsLog
日志相关,构建log字段,类型为org.apache.commons.logging.Log。使用的时候要引入相对应的日志依赖。
源码:
@CommonsLog
public class User {
}
编译后:
public class User {
private static final org.apache.commons.logging.Log log =
org.apache.commons.logging.LogFactory.getLog(User.class);
}
- @Flogger、@JBossLog、@Log、@Log4j、@Log4j2、@Slf4j、@XSlf4j
和@CommonsLog一样都是日志相关,区别是Log类型不同。
@Flogger:
private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
@JBossLog:
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(User.class);
@Log:
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(User.class.getName());
@Log4j:
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(User.class);
@Log4j2:
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(User.class);
@Slf4j:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(User.class);
@XSlf4j:
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(User.class);
关于Lombok的详细介绍,请戳《Lombok-高级篇》