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插入式注解处理器)

注解处理器的工作原理

image-20201105181646111

Lombok常用注解

image-20201105181839590

@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
    27
    package 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 {

    @Getter(lazy = true)
    private final String field1 = "xiaohong";

    @Getter(value = AccessLevel.PRIVATE, onMethod_ = {@NotNull})
    private String field2;

    @Getter
    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));
    }

    @NotNull
    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
    24
    package 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 {

    @Setter
    private String field1;

    @Setter(value = AccessLevel.PRIVATE, onParam_ = {@NotNull})
    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(@NotNull 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
    42
    package com.java.example.lombok;

    import lombok.Setter;
    import lombok.ToString;
    import org.testng.annotations.Test;

    /**
    * ToString注解 生成toString方法
    * 必须作用在类上
    *
    * @author jingLv
    * @date 2020/11/06
    */
    @ToString(
    includeFieldNames = false,
    //exclude = {"field1"},
    // of = {"field1"},
    doNotUseGetters = true
    )
    public class ToStringTest {
    @Setter
    private String field1;
    @Setter
    private String field2;

    public String getField2() {
    System.out.println("调用get方法!");
    return this.field2;
    }

    /**
    * 如果:doNotUseGetters = true
    * 则该语句不会输出:System.out.println("调用get方法!");
    */
    @Test
    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
    18
    package com.java.example.lombok;

    import lombok.EqualsAndHashCode;

    /**
    * EqualsAndHashCodeTest注解,生成Equals方法和HashCode方法
    * 作用在类上
    *
    * @author jingLv
    * @date 2020/11/06
    */
    @EqualsAndHashCode(
    exclude = {"field1"}
    )
    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
    16
    package com.java.example.lombok;

    import lombok.Data;

    /**
    * Data注解,集成的一个注解,包含@Getter @Setter @ToString @ToEqualsAndHashCode
    *
    * @author jingLv
    * @date 2020/11/06
    */
    @Data
    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
    24
    package 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
    17
    package com.java.example.lombok;

    import lombok.NonNull;

    /**
    * NonNull注解,生成非空的检查
    * 作用在方法的入参和属性上
    *
    * @author jingLv
    * @date 2020/11/06
    */
    public class NonNullTest {

    public NonNullTest(@NonNull 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(@NonNull 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
    26
    package com.java.example.lombok;

    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;

    /**
    * 三种构造函数注解
    * AllArgsConstructor -- 全参构造函数
    * NoArgsConstructor -- 无参构造函数
    * RequiredArgsConstructor -- 必要参数的构造函数
    *
    * @author jingLv
    * @date 2020/11/06
    */
    @RequiredArgsConstructor
    public class ConstructorTest {

    // final类型的,在构造的时候必须初始化
    private final String field1;

    // 非空校验的,构造的时候也必须初始化
    @NonNull
    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;
    @NonNull
    private String field2;
    private String field3;

    public ConstructorTest(String field1, @NonNull 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
    27
    package 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 {
    @Cleanup FileInputStream fileInputStream = new FileInputStream(in);
    @Cleanup FileOutputStream fileOutputStream = new FileOutputStream(out);

    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
    20
    package com.java.example.lombok;

    import lombok.extern.slf4j.Slf4j;
    import org.testng.annotations.Test;

    /**
    * Slf4j注解
    *
    * @author jingLv
    * @date 2020/11/06
    */
    @Slf4j
    public class LogTest {

    @Test
    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() {
    }

    @Test
    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
    55
    package 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
    */
    @Builder
    @Getter
    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
    64
    package 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
    */
    @Builder
    @Getter
    public class BuilderTest {

    /**
    * 静态属性,不能赋值
    */
    private static String staticField;

    /**
    * final属性
    */
    private final String finalField;

    /**
    * 已初始化的final属性,不能赋值
    */
    private final String initFinalField = "已初始化的final字段";

    /**
    * 普通属性
    */
    private String field;

    /**
    * 集合类的属性,注意:括号里带字段名
    */
    @Singular("listField")
    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));
    }
    }

    执行结果:

    image-20201109102905459

Lombok插件安装

IntelliJ IDEA –> Preferences –> Plugins –> 搜索lombok 下载安装 安装完成重启idea即可

image-20201005114344180

安装完成之后出现如下问题的解决方案:

image-20201005120211047

Lombok引入依赖

maven项目中引入如下坐标:

1
2
3
4
5
6
7
<!--Lombok的jar包引入-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>

provided表示jar包是运行在编译时期, 当程序编译成源代码之后,这个jar包则不会在源代码层面提现

Lombok的优缺点

Lombok的优点

  • 通过注解自动生成样板代码,提高开发效率
  • 代码简洁,只关注相关属性
  • 新增属性后,无需刻意修改相关方法

Lombok的缺点

  • 降低了源代码的可读性和完整性
  • 加大对问题排查的难度
  • 需要IDE的相关插件的支持

日志体系

image-20201106180748162

  • 黄色部分是接口
  • 白色部分是实现打印日志框架
  • 红色标注是日志桥接包,根据箭头指向,将日志类型转换