前言
整理一些Lombok的常用注解和注意事项(几乎包含所有主流注解了)。
Lombok是通过在编译阶段进行字节码增强实现的,它利用Java的注解处理器机制,根据注解生成相应的代码,可以大幅减少 Java 代码的冗余和重复,提高开发效率。
@Data
@Data
是 Lombok 提供的一个注解,它是一个组合注解,包含了以下注解的功能:
@Getter
:生成属性的 getter 方法。@Setter
:生成属性的 setter 方法。@ToString
:生成 toString 方法,用于输出对象的字符串表示。@EqualsAndHashCode
:生成 equals 和 hashCode 方法,用于对象的比较和哈希计算。
使用 @Data
注解可以简化 POJO 类的编写。
以下是使用 @Data
注解的示例代码:
1 | // author: SilenceZheng66 |
编译器生成的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
// 来自Java编译器,隐式无参构造函数
public LombokTest() {
}
// 来自 @Getter
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
// 来自 @Setter
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
// 来自 @EqualsAndHashCode
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else if (this.getId() != other.getId()) {
return false;
} else {
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;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}
public int hashCode() {
int PRIME = true;
int result = 1;
result = result * 59 + this.getId();
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
// 来自 @ToString
public String toString() {
return "LombokTest(id=" + this.getId() + ", name=" + this.getName() + ")";
}
}
需要注意的是,@Data
注解会生成所有属性的 getter 和 setter 方法,如果需要对某些属性进行特殊处理,可以使用其他注解,对指定的属性进行定制化配置。
@NoArgsConstructor
@NoArgsConstructor
是 Lombok 提供的一个注解,用于自动生成无参构造函数。它可以用在类上,表示为该类生成一个无参构造函数。如果类已经包含了其他有参构造函数,使用 @NoArgsConstructor
不会覆盖已有的构造函数。
以下是使用 @NoArgsConstructor
注解的示例代码:1
2
3
4
5
6
7
8
9
10
11// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
public LombokTest(int id, String name) {
this.id = id;
this.name = name;
}
}
编译器生成的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
public LombokTest(int id, String name) {
this.id = id;
this.name = name;
}
public LombokTest() {
}
}
@AllArgsConstructor
@AllArgsConstructor
是 Lombok 提供的一个注解,用于自动生成包含所有属性的构造函数。它可以用在类上,表示为该类生成一个包含所有属性的构造函数。注意此时类中不可以包含全参构造函数代码。
以下是使用 @AllArgsConstructor
注解的示例代码:1
2
3
4
5
6
7
8
9
10// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
public LombokTest(int id) {
this.id = id;
}
}
编译器生成的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
public LombokTest(int id) {
this.id = id;
}
public LombokTest(int id, String name) {
this.id = id;
this.name = name;
}
}
@Builder
@Builder
是 Lombok 提供的一个注解,用于自动生成构建器模式相关的代码。它可以用在类上,表示为该类生成一个构建器,用于简化创建对象的过程。使用构建器模式可以避免过多的构造函数重载,并提供更灵活的对象创建方式。
以下是使用 @Builder
注解的示例代码:1
2
3
4
5
6// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
}
编译器生成的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
// Lombok自动产生
LombokTest(int id, String name) {
this.id = id;
this.name = name;
}
public static LombokTestBuilder builder() {
return new LombokTestBuilder();
}
public static class LombokTestBuilder {
private int id;
private String name;
LombokTestBuilder() {
}
public LombokTestBuilder id(int id) {
this.id = id;
return this;
}
public LombokTestBuilder name(String name) {
this.name = name;
return this;
}
public LombokTest build() {
return new LombokTest(this.id, this.name);
}
public String toString() {
return "LombokTest.LombokTestBuilder(id=" + this.id + ", name=" + this.name + ")";
}
}
}
这样我们就可以通过构造器模式创建对象:
1 | // author: SilenceZheng66 |
@NonNull
将@NonNull
注解放在属性上,表示该属性不能为null
,否则会在运行时抛出NullPointerException
。
以下是使用 @NonNull
注解的示例代码:1
2
3
4
5
6// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
}
编译器生成的结果如下:1
2
3
4
5
6
7
8// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
public LombokTest() {
}
}
但注意这里将 @NonNull
注解用于primitive
是无意义的,原始类型本身就不能是null
。
@RequiredArgsConstructor
将@RequiredArgsConstructor
注解放在类上,它会生成一个包含所有标记了@NonNull
注解的属性的构造函数。
以下是使用 @RequiredArgsConstructor
注解的示例代码:1
2
3
4
5
6
7
8
9
10// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
private String aString;
private Double aDouble;
}
编译器生成的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// author: SilenceZheng66
public class LombokTest {
private int id;
private String name;
private String aString;
private Double aDouble;
public LombokTest( String aString, Double aDouble){
if (aString == null) {
throw new NullPointerException("aString is marked non-null but is null");
} else if (aDouble == null) {
throw new NullPointerException("aDouble is marked non-null but is null");
} else {
this.aString = aString;
this.aDouble = aDouble;
}
}
}
@SneakyThrows
将@SneakyThrows
注解放在方法上,它会自动将受检异常转换为非受检异常抛出,避免在代码中显式地处理受检异常。
以下是使用 @RequiredArgsConstructor
注解的示例代码:1
2
3
4
5
6
7
8// author: SilenceZheng66
public class Example {
public void doSomething() {
// 这里抛出了一个受检异常,但是不需要显式地处理它
throw new Exception("This is a checked exception");
}
}
编译器生成的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13// author: SilenceZheng66
public class Example {
public Example() {
}
public void doSomething() {
try {
throw new Exception("This is a checked exception");
} catch (Throwable var2) {
throw var2;
}
}
}
如果不使用该注解,通常我们需要如此处理:1
2
3
4
5
6
7
8
9
10
11
12// author: SilenceZheng66
public class Example {
public void doSomething() throws Exception {
// 这里抛出了一个受检异常,需要显式地处理它
throw new Exception("This is a checked exception");
}
public static void main(String[] args) throws Exception {
Example example = new Example();
example.doSomething();
}
}
关于受检异常和非受检异常:
java.lang.Throwable
是Java中所有错误和异常的根类。它是一个类层次结构的顶层类,表示可以被抛出的任何问题,包括错误(Error
)和异常(Exception
)。
Throwable
类包含以下几个重要的子类:
Error
: 表示严重的系统错误,通常由Java虚拟机(JVM)报告,例如OutOfMemoryError
、StackOverflowError
等。Error
类的实例通常表示不可恢复的错误情况,应用程序通常不应该捕获和处理Error
。
Exception
: 表示可被捕获和处理的异常。Exception
类又分为两类:
受检异常(Checked Exception):继承自
Exception
的子类,但不继承自RuntimeException
的异常。受检异常在方法签名中必须显式地声明,或者在方法内部捕获和处理,否则编译器会报错。例如,IOException
、SQLException
等属于受检异常。非受检异常(Unchecked Exception):继承自
RuntimeException
的异常。非受检异常不需要在方法签名中显式地声明,也可以不在方法内部捕获和处理。通常是由程序编程错误引起的,例如NullPointerException
、ArrayIndexOutOfBoundsException
等。
Throwable
类定义了以下一些重要的方法:
getMessage()
: 获取关于异常的详细信息。toString()
: 返回异常的字符串表示,包括异常的类名和详细信息。printStackTrace()
: 在控制台打印异常的堆栈跟踪信息,用于调试和错误定位。getCause()
: 获取导致当前异常的原因(即导致当前异常抛出的其他异常)。
Throwable
类的子类可以通过继承它的方法和添加自己的方法来定义特定类型的错误和异常。
其他一些注解
@Cleanup
:将@Cleanup
注解放在需要进行资源关闭的属性上,它会自动生成资源的关闭代码,用于简化资源管理,特别是对于实现java.io.Closeable
接口的资源。
@Getter(lazy = true)
:将@Getter(lazy = true)
注解放在属性上,它会生成属性的懒加载 getter 方法,在第一次调用该方法时才会计算并返回属性的值。
还有一些日志相关的注解,等写Java日志框架时再一并写了吧。
后记
首发于 silencezheng.top,转载请注明出处。