Java之Lombok使用
Java之Lombok使用
Lombok
Project Lombok是一个java库,可以自动插入编辑器构建工具,为您的Java增添色彩。
永远不要再写另一个getter或equals方法,使用一个注释,您的类具有一个功能齐全的构建器,自动化您的日志记录变量等等。
–Lombok官网
Lombok实现原理
注解的两种解析方式:
- 运行时解析
- 例如Spring AOP切面,这些注解都是在程序运行的时候,通过反射来获取注解值
- 缺点:只有在程序运行的时候才能获取到注解值,导致运行时的代码效率很低,并且如果想在编译阶段利用注解进行检查就无能为力了
- 编译时解析
- lombok使用的是编译时解析
编译时解析的两种机制
- Annotation Processing Tool(注解处理器)
- JDK1.5时随着annotation引入的,是一个命令行工具,能够提供构建时基于源代码对程序结构的读取功能,能够通过运行注解处理器来生成新的中间文件,而影响编译过程
- JDK1.8已移除
- Pluggable Annontation Processing API(JSR269插入式注解处理器)
注解处理器的工作原理
Lombok常用注解
@Getter注解
说明:Getter注解,为属性生成get方法
作用位置:可作用在类上或属性上
- 作用在类上,为类下的所有属性生成get方法
- 作用在属性上,只为这一个属性生成get方法
属性:
- AccessLevel – 访问级别
- onMethod_ – set方法增加注解
- onParam_ – 方法的入参上增加自定义的注解
- lazy–作用在final字段上,设为true的时候,会为常量值进行懒加载
代码示例:
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
27package com.java.example.lombok;
import com.sun.istack.internal.NotNull;
import lombok.AccessLevel;
import lombok.Getter;
/**
* Getter注解 为属性生成get方法
* 可作用在类上或属性上
* 作用在类上,为类下的所有属性生成get方法
* 作用在属性上,只为这一个属性生成get方法
*
* @author jingLv
* @date 2020/11/06
*/
public class GetterTest {
private final String field1 = "xiaohong";
private String field2;
private String field3;
}
编译后的代码示例:
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//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import com.sun.istack.internal.NotNull;
import java.util.concurrent.atomic.AtomicReference;
public class GetterTest {
private final AtomicReference<Object> field1 = new AtomicReference();
private String field2;
private String field3;
public GetterTest() {
}
public String getField1() {
Object value = this.field1.get();
if (value == null) {
synchronized(this.field1) {
value = this.field1.get();
if (value == null) {
String actualValue = "xiaohong";
value = "xiaohong" == null ? this.field1 : "xiaohong";
this.field1.set(value);
}
}
}
return (String)((String)(value == this.field1 ? null : value));
}
private String getField2() {
return this.field2;
}
public String getField3() {
return this.field3;
}
}
@Setter注解
说明:Setter注解,为属性生成set方法
作用位置:可作用在类上或属性上
- 作用在类上,为类下的所有属性生成set方法
- 作用在属性上,只为这一个属性生成set方法
属性:
- AccessLevel – 访问级别
- onMethod_ – set方法增加注解
- onParam_ – 方法的入参上增加自定义的注解
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.java.example.lombok;
import com.sun.istack.internal.NotNull;
import lombok.AccessLevel;
import lombok.Setter;
/**
* Setter注解 为属性生成set方法
* 可作用在类上或属性上
* 作用在类上,为类下的所有属性生成set方法
* 作用在属性上,只为这一个属性生成set方法
*
* @author jingLv
* @date 2020/11/06
*/
public class SetterTest {
private String field1;
private String field2;
}
编译后的代码示例:
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//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import com.sun.istack.internal.NotNull;
public class SetterTest {
private String field1;
private String field2;
public SetterTest() {
}
public void setField1(String field1) {
this.field1 = field1;
}
private void setField2( String field2){
this.field2 = field2;
}
}@ToString注解
说明:ToString注解,生成toString方法
作用位置:只可作用在类上
属性:
- includeFieldNames – 设为false生成的toString方法只有属性名没有属性值
- exclude – 排除属性
- of – 强制指定属性,会与exclude冲突,如果同时存在,exclude将会被忽略
- callSuper – 调用父类的toString的输出包含到输出中
- doNotUseGetters – 设为true,不会调用属性的get方法获取属性值
- onlyExplicitlyIncluded – 设为true,准确指定要使用的字段
代码示例:
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
42package com.java.example.lombok;
import lombok.Setter;
import lombok.ToString;
import org.testng.annotations.Test;
/**
* ToString注解 生成toString方法
* 必须作用在类上
*
* @author jingLv
* @date 2020/11/06
*/
public class ToStringTest {
private String field1;
private String field2;
public String getField2() {
System.out.println("调用get方法!");
return this.field2;
}
/**
* 如果:doNotUseGetters = true
* 则该语句不会输出:System.out.println("调用get方法!");
*/
public void test() {
ToStringTest toStringTest = new ToStringTest();
toStringTest.setField1("xiaohong");
toStringTest.setField2("xiaohuang");
System.out.println(toStringTest.toString());
}
}@EqualsAndHashCode注解
说明:EqualsAndHashCodeTest注解,生成Equals方法和HashCode方法
作用位置:作用在类上
属性:
- exclude – 排除属性
- of – 强制指定属性,会与exclude冲突,如果同时存在,exclude将会被忽略
- callSuper – 调用父类的equals和hashCode方法
- doNotUseGetters – 设为true,不会调用属性的get方法获取属性值
- onParam – 方法的入参上增加自定义的注解
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.java.example.lombok;
import lombok.EqualsAndHashCode;
/**
* EqualsAndHashCodeTest注解,生成Equals方法和HashCode方法
* 作用在类上
*
* @author jingLv
* @date 2020/11/06
*/
public class EqualsAndHashCodeTest {
private String field1;
private String field2;
}
编译后的代码示例:
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//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
public class EqualsAndHashCodeTest {
private String field1;
private String field2;
public EqualsAndHashCodeTest() {
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof EqualsAndHashCodeTest)) {
return false;
} else {
EqualsAndHashCodeTest other = (EqualsAndHashCodeTest)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$field2 = this.field2;
Object other$field2 = other.field2;
if (this$field2 == null) {
if (other$field2 != null) {
return false;
}
} else if (!this$field2.equals(other$field2)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeTest;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $field2 = this.field2;
int result = result * 59 + ($field2 == null ? 43 : $field2.hashCode());
return result;
}
}@Data注解
说明:Data注解,集成的一个注解,包含@Getter @Setter @ToString @ToEqualsAndHashCode
作用位置:作用在类上
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package com.java.example.lombok;
import lombok.Data;
/**
* Data注解,集成的一个注解,包含@Getter @Setter @ToString @ToEqualsAndHashCode
*
* @author jingLv
* @date 2020/11/06
*/
public class DataTest {
private String field1;
private String field2;
}
编译后的代码示例:
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
74
75
76
77
78
79
80
81
82
83//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
public class DataTest {
private String field1;
private String field2;
public DataTest() {
}
public String getField1() {
return this.field1;
}
public String getField2() {
return this.field2;
}
public void setField1(String field1) {
this.field1 = field1;
}
public void setField2(String field2) {
this.field2 = field2;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof DataTest)) {
return false;
} else {
DataTest other = (DataTest)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$field1 = this.getField1();
Object other$field1 = other.getField1();
if (this$field1 == null) {
if (other$field1 != null) {
return false;
}
} else if (!this$field1.equals(other$field1)) {
return false;
}
Object this$field2 = this.getField2();
Object other$field2 = other.getField2();
if (this$field2 == null) {
if (other$field2 != null) {
return false;
}
} else if (!this$field2.equals(other$field2)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof DataTest;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $field1 = this.getField1();
int result = result * 59 + ($field1 == null ? 43 : $field1.hashCode());
Object $field2 = this.getField2();
result = result * 59 + ($field2 == null ? 43 : $field2.hashCode());
return result;
}
public String toString() {
return "DataTest(field1=" + this.getField1() + ", field2=" + this.getField2() + ")";
}
}
@Val注解
说明:Val注解,弱语言中的变量声明,可以接收任何类型的参数,通过变量的值推断出变量的类型是什么
作用位置: 作用在本地方法
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.java.example.lombok;
import lombok.val;
import java.util.ArrayList;
/**
* Val注解,弱语言中的变量声明,可以接收任何类型的参数
* 作用在本地方法
* 通过变量的值推断出变量的类型是什么
*
* @author jingLv
* @date 2020/11/06
*/
public class ValTest {
public ValTest() {
val field = "xiaohong";
val list = new ArrayList<String>();
list.add(field);
}
}
编译后的代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import java.util.ArrayList;
public class ValTest {
public ValTest() {
String field = "xiaohong";
ArrayList<String> list = new ArrayList();
list.add("xiaohong");
}
}
@NonNull注解
说明:NonNull注解,生成非空的检查
作用位置:作用在方法的入参和属性上
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.java.example.lombok;
import lombok.NonNull;
/**
* NonNull注解,生成非空的检查
* 作用在方法的入参和属性上
*
* @author jingLv
* @date 2020/11/06
*/
public class NonNullTest {
public NonNullTest( String field){
System.out.println(field);
}
}
编译后的代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import lombok.NonNull;
public class NonNullTest {
public NonNullTest( String field){
if (field == null) {
throw new NullPointerException("field is marked non-null but is null");
} else {
System.out.println(field);
}
}
}@Constructor注解
说明:构造函数注解,提供了三种构造函数
- AllArgsConstructor – 全参构造函数
- NoArgsConstructor – 无参构造函数
- RequiredArgsConstructor – 必要参数的构造函数
作用位置:作用在类上
代码示例:
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
26package com.java.example.lombok;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
/**
* 三种构造函数注解
* AllArgsConstructor -- 全参构造函数
* NoArgsConstructor -- 无参构造函数
* RequiredArgsConstructor -- 必要参数的构造函数
*
* @author jingLv
* @date 2020/11/06
*/
public class ConstructorTest {
// final类型的,在构造的时候必须初始化
private final String field1;
// 非空校验的,构造的时候也必须初始化
private String field2;
private String field3;
}
编译后的代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import lombok.NonNull;
public class ConstructorTest {
private final String field1;
private String field2;
private String field3;
public ConstructorTest(String field1, String field2){
if (field2 == null) {
throw new NullPointerException("field2 is marked non-null but is null");
} else {
this.field1 = field1;
this.field2 = field2;
}
}
}
@Cleanup注解
说明:Cleanup注解,生成对资源关闭的操作代码
作用位置:需要关闭资源的位置
代码示例:
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
27package com.java.example.lombok;
import lombok.Cleanup;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Cleanup注解,生成对资源关闭的操作代码
*
* @author jingLv
* @date 2020/11/06
*/
public class CleanupTest {
public void copyFile(String in, String out) throws IOException {
new FileInputStream(in); FileInputStream fileInputStream =
new FileOutputStream(out); FileOutputStream fileOutputStream =
int r;
while ((r = fileInputStream.read()) != -1) {
fileOutputStream.write(r);
}
}
}
编译后的代码示例:
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//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
public class CleanupTest {
public CleanupTest() {
}
public void copyFile(String in, String out) throws IOException {
FileInputStream fileInputStream = new FileInputStream(in);
try {
FileOutputStream fileOutputStream = new FileOutputStream(out);
int r;
try {
while((r = fileInputStream.read()) != -1) {
fileOutputStream.write(r);
}
} finally {
if (Collections.singletonList(fileOutputStream).get(0) != null) {
fileOutputStream.close();
}
}
} finally {
if (Collections.singletonList(fileInputStream).get(0) != null) {
fileInputStream.close();
}
}
}
}
@Slf4j注解
说明:Slf4j注解,简化日志引入方法
作用位置:作用在类上
注意:需要使用系统内置的日志框架输出日志,引入slf4j jar支持
1
2
3
4
5<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.29</version>
</dependency>代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.java.example.lombok;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
/**
* Slf4j注解
*
* @author jingLv
* @date 2020/11/06
*/
public class LogTest {
public void func() {
log.error("错误日志!!");
}
}
编译后的代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
public class LogTest {
private static final Logger log = LoggerFactory.getLogger(LogTest.class);
public LogTest() {
}
public void func() {
log.error("错误日志!!");
}
}
@Builder注解
说明:Builder注解,简化对象创建过程
作用位置:作用在类上
代码示例:
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
55package com.java.example.lombok;
import com.alibaba.fastjson.JSON;
import lombok.Builder;
import lombok.Getter;
/**
* Builder和Singular注解
* Builder注解,将对象创建和对象的使用完全分离,对象的创建只能用Builder创建,创建完成对象不可变,只能对这个对象使用,不能再对这个对象进行更改
*
* @author jingLv
* @date 2020/11/06
*/
public class BuilderTest {
/**
* 静态属性,不能赋值
*/
private static String staticField;
/**
* final属性
*/
private final String finalField;
/**
* 已初始化的final属性,不能赋值
*/
private final String initFinalField = "已初始化的final字段";
/**
* 普通属性
*/
private String field;
/**
* main方法
*
* @param args
*/
public static void main(String[] args) {
BuilderTest build = BuilderTest
// builder创建一个可以链式赋值的对象
.builder()
// 为这个对象的"每个"字段赋值
.finalField("手动赋值FinalField字段")
.field("手动赋值Field字段")
// build方法来创建对象。完成了对象的创建。此时创建出来的对象是不可变的!
.build();
System.out.println(JSON.toJSONString(build, true));
}
}
编译后的代码示例:
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//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.java.example.lombok;
import com.alibaba.fastjson.JSON;
public class BuilderTest {
private static String staticField;
private final String finalField;
private final String initFinalField = "已初始化的final字段";
private String field;
public static void main(String[] args) {
BuilderTest build = builder().finalField("手动赋值FinalField字段").field("手动赋值Field字段").build();
System.out.println(JSON.toJSONString(build, true));
}
BuilderTest(String finalField, String field) {
this.finalField = finalField;
this.field = field;
}
public static BuilderTest.BuilderTestBuilder builder() {
return new BuilderTest.BuilderTestBuilder();
}
public String getFinalField() {
return this.finalField;
}
public String getInitFinalField() {
this.getClass();
return "已初始化的final字段";
}
public String getField() {
return this.field;
}
// 内部的类来持有化需要赋值的属性,并且使用这个属性来创建需要的创建的对象
public static class BuilderTestBuilder {
private String finalField;
private String field;
BuilderTestBuilder() {
}
public BuilderTest.BuilderTestBuilder finalField(String finalField) {
this.finalField = finalField;
return this;
}
public BuilderTest.BuilderTestBuilder field(String field) {
this.field = field;
return this;
}
public BuilderTest build() {
return new BuilderTest(this.finalField, this.field);
}
public String toString() {
return "BuilderTest.BuilderTestBuilder(finalField=" + this.finalField + ", field=" + this.field + ")";
}
}
}
@Singular注解
说明:Singular注解配合@Builder注解,简化集合类型操作
作用位置:作用在集合属性上
注意:需要结合Builder注解一起使用
代码示例:
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
64package com.java.example.lombok;
import com.alibaba.fastjson.JSON;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
/**
* Builder和Singular注解
* Builder注解,将对象创建和对象的使用完全分离,对象的创建只能用Builder创建,创建完成对象不可变,只能对这个对象使用,不能再对这个对象进行更改
*
* @author jingLv
* @date 2020/11/06
*/
public class BuilderTest {
/**
* 静态属性,不能赋值
*/
private static String staticField;
/**
* final属性
*/
private final String finalField;
/**
* 已初始化的final属性,不能赋值
*/
private final String initFinalField = "已初始化的final字段";
/**
* 普通属性
*/
private String field;
/**
* 集合类的属性,注意:括号里带字段名
*/
private List<String> listField;
/**
* main方法
*
* @param args
*/
public static void main(String[] args) {
BuilderTest build = BuilderTest
// builder创建一个可以链式赋值的对象
.builder()
// 为这个对象的"每个"字段赋值
.finalField("手动赋值FinalField字段")
.field("手动赋值Field字段")
.listField("xiaohong")
// build方法来创建对象。完成了对象的创建。此时创建出来的对象是不可变的!
.build();
System.out.println(JSON.toJSONString(build, true));
}
}执行结果:
Lombok插件安装
IntelliJ IDEA –> Preferences –> Plugins –> 搜索lombok 下载安装 安装完成重启idea即可
安装完成之后出现如下问题的解决方案:
Lombok引入依赖
maven项目中引入如下坐标:
1 | <!--Lombok的jar包引入--> |
provided表示jar包是运行在编译时期, 当程序编译成源代码之后,这个jar包则不会在源代码层面提现
Lombok的优缺点
Lombok的优点
- 通过注解自动生成样板代码,提高开发效率
- 代码简洁,只关注相关属性
- 新增属性后,无需刻意修改相关方法
Lombok的缺点
- 降低了源代码的可读性和完整性
- 加大对问题排查的难度
- 需要IDE的相关插件的支持
日志体系
- 黄色部分是接口
- 白色部分是实现打印日志框架
- 红色标注是日志桥接包,根据箭头指向,将日志类型转换