Lombok工具 : 常用注解介绍 (全)

文章目录

  • 介绍
  • 引入Maven依赖
  • 常用的注解
    • @NoArgsConstructor/@AllArgsConstructor
    • @RequiredArgsConstructor
    • @Getter/@Setter
    • @ToString/@EqualsAndHashCode
    • @Data
    • @Builder
    • @Accessors
  • 其他注解
    • @SneakyThrows
    • @Value
    • @Cleanup
    • @NotNull
    • @Synchronized
    • @Log、@Log4j、@Slf4j、@Log4j2、@CommonsLog、@XSlf4j等日志注解
      • @Log注解
      • @Log4j注解
      • @Log4j2注解
      • @Slf4j注解
    • @Delegate
    • @Singular

介绍

官方网址 : https://projectlombok.org/

Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的Java模型对象(POJO)。

在开发环境中使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。

引入Maven依赖

采用最新版本 1.18.24

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
    <version>1.18.24</version>
</dependency>

常用的注解

@NoArgsConstructor/@AllArgsConstructor

  • @NoArgsConstructor/@AllArgsConstructor就是为该类产生无参的构造方法和包含所有参数的构造方法

测试案例1:

@AllArgsConstructor
public class Demo extends Parent{
    private String name;
    private int age;
}

@AllArgsConstructor
@NoArgsConstructor
class Parent {
    private Integer id;
}

编译后的两个class文件如下:

此注解并不会把父类的属性id拿到Demo的构造器里面去,这是需要注意的地方。

public class Demo {
    private String name;
    private int age;

    public Demo() {
    }

    public Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Parent {
    private Integer id;

    public Parent(Integer id) {
        this.id = id;
    }

    public Parent() {
    }
}

通过IDEA的类结构, 也可以看出来生成了哪些东西


测试案例2:

通过 @AllArgsConstructor(access = AccessLevel.PROTECTED) , 可以指定构造器的访问权限

@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class Demo{
    private String name;
    private int age;
}

编译后生成:

public class Demo {
    private String name;
    private int age;

    protected Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }
}


测试案例3:

@AllArgsConstructor(access = AccessLevel.PROTECTED, staticName = “test”)

@AllArgsConstructor(access = AccessLevel.PROTECTED, staticName = "test")
public class Demo{
    private final int finalVal = 10;
    private String name;
    private int age;
}

编译后 :

public class Demo {
    private String name;
    private int age;

    private Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    protected static Demo test(String name, int age) {
        return new Demo(name, age);
    }
}

上面效果为:可以指定生成的构造器的访问权限。但是如果指定了一个静态方法,那么构造器会自动会被private,只通过静态方法对外提供访问,并且我们发现final的属性值,是不会放进构造函数里面的。

@NoArgsConstructor的使用方式同@AllArgsConstructor

@RequiredArgsConstructor

@RequiredArgsConstructor注解则会将类中所有带有@NonNull注解 / org.jetbrains.annotations.NotNull注解的或者带有final修饰的成员变量生成对应的构造方法

测试案例:

@RequiredArgsConstructor
public class Demo {

    @NonNull
    private final int finalVal;
    @NonNull
    private String name;
    @NonNull
    private int age;
}

编译后生成:

import lombok.NonNull;

public class Demo {
    @NonNull
    private final int finalVal;
    @NonNull
    private String name;
    @NonNull
    private int age;

    public Demo(@NonNull int finalVal, @NonNull String name, @NonNull int age) {
        if (name == null) {
            throw new NullPointerException("name is marked non-null but is null");
        } else {
            this.finalVal = finalVal;
            this.name = name;
            this.age = age;
        }
    }
}

解释:该注解会识别@NonNull字段和final修饰得字段,然后以该字段为元素生成一个构造函数。

如果所有字段都没有@NonNull注解,那效果同@NoArgsConstructor ;
@RequiredArgsConstructor 注解的参数, 和其他两个注解一样

注意: 当然这三个生成构造器的注解,要求成员变量都是非静态的, 否则静态变量不会在构造器中被赋值

@Getter/@Setter

这一对注解从名字上就很好理解,用在成员变量上面或者类上面,相当于为成员变量生成对应的get和set方法,同时还可以为生成的方法指定访问修饰符,当然,默认为public

// 如果指定在类上,所有字段都会生成get/set方法
// 指定在字段上, 只有标注的字段才会生成get/set方法
@Getter
@Setter
public class Demo {

    private String name;
    private int age;
}

这两个注解直接用在类上,可以为此类里的所有非静态成员变量生成对应的get和set方法。如果是final变量,那就只会有get方法

@ToString/@EqualsAndHashCode

这两个注解也比较好理解,就是生成toString,equals和hashcode方法,同时后者还会生成一个canEqual方法,用于判断某个对象是否是当前类的实例。生成方法时只会使用类中的非静态成员变量。

@ToString
@EqualsAndHashCode
public class Demo {

    private String name;
    private int age;
}

有些关键的属性,可以控制toString的输出,我们可以了解一下:

//@EqualsAndHashCode也有类似的下面的属性,
@ToString(
        includeFieldNames = true, //是否使用字段名
        exclude = {"name"}, //排除某些字段
        of = {"age"}, //只使用某些字段
        callSuper = true //是否让父类字段也参与 默认false
)

@Data

相当于注解集合。效果等同于 @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor 效果同和这5个注解的效果

需要注意的是,这里不包括@NoArgsConstructor和@AllArgsConstructor

  • 所以, 一般使用@Data时,要配合这两个注解一起使用
@Data
public class Demo {
    private String name;
    private int age;
}

@Builder

@Builder提供了一种比较推崇的构建值对象的方式; 非常推荐的一种构建值对象的方式。

缺点就是父类的属性不能产于builder

标注@Builder的类, 会在类内部生成一个内部类,用于生成值对象

@Builder
public class Demo {
    private final int finalVal = 10;

    private String name;
    private int age;
}

编译后生成:

public class Demo {
    private final int finalVal = 10;
    private String name;
    private int age;

    Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static Demo.DemoBuilder builder() {
        return new Demo.DemoBuilder();
    }

    public static class DemoBuilder {
        private String name;
        private int age;

        DemoBuilder() {
        }

        public Demo.DemoBuilder name(String name) {
            this.name = name;
            return this;
        }

        public Demo.DemoBuilder age(int age) {
            this.age = age;
            return this;
        }

        public Demo build() {
            return new Demo(this.name, this.age);
        }

        public String toString() {
            return "Demo.DemoBuilder(name=" + this.name + ", age=" + this.age + ")";
        }
    }
}

使用方式:

public class Main {

    public static void main(String[] args) {
        Demo demo = Demo.builder().name("zss").age(20).build();
        System.out.println(demo);
    }
}

一般我们给POJO类, 标注的Lombok注解, 百分之90就是这4个 : @Data, @NoArgsConstructor, @AllArgsConstructor, @Builder

@Accessors

@Accessors 一个为getter和setter方法设计的更流畅的注解
这个注解要搭配@Getter与@Setter使用,用来修改默认的setter与getter方法的形式。

@Accessors属性详解

  • fluent 属性 : 链式的形式 这个特别好用,方法连缀越来越方便了
  • chain 属性 : 流式的形式(若无显示指定chain的值,也会把chain设置为true)
  • prefix 属性 : 生成指定前缀的属性的getter与setter方法,并且生成的getter与setter方法时会去除前缀

测试不使用@Accessors时

fluent属性

默认为false,当该值为 true 时,对应字段的 getter 方法前面就没有 get,setter 方法就不会有 set。

编译后生成:

public class Demo {
    private final int finalVal = 10;
    private String xxName;
    private int yyAge;

    public Demo() {
    }

    public int finalVal() {
        Objects.requireNonNull(this);
        return 10;
    }

    public String xxName() {
        return this.xxName;
    }

    public int yyAge() {
        return this.yyAge;
    }

    public Demo xxName(String xxName) {
        this.xxName = xxName;
        return this;
    }

    public Demo yyAge(int yyAge) {
        this.yyAge = yyAge;
        return this;
    }

    public String toString() {
        int var10000 = this.finalVal();
        return "Demo(finalVal=" + var10000 + ", xxName=" + this.xxName() + ", yyAge=" + this.yyAge() + ")";
    }
}

使用:

public class Main {

    public static void main(String[] args) {
        Demo demo = new Demo();
        // setter方法; 这里包含了chain=true的功能,可以链式设置值
        demo.xxName("lucky").yyAge(20);
        // getter方法
        System.out.println(demo.xxName() + "," + demo.yyAge());
        System.out.println("demo = " + demo);
    }
}

chain属性

不写默认为false,当该值为 true 时,对应字段的 setter 方法调用后,会返回当前对象, 进行链式设置值

编译后生成:

public class Demo {
    private final int finalVal = 10;
    private String xxName;
    private int yyAge;

    public Demo() {
    }

    public int getFinalVal() {
        Objects.requireNonNull(this);
        return 10;
    }

    public String getXxName() {
        return this.xxName;
    }

    public int getYyAge() {
        return this.yyAge;
    }

    public Demo setXxName(String xxName) {
        this.xxName = xxName;
        return this;
    }

    public Demo setYyAge(int yyAge) {
        this.yyAge = yyAge;
        return this;
    }

    public String toString() {
        int var10000 = this.getFinalVal();
        return "Demo(finalVal=" + var10000 + ", xxName=" + this.getXxName() + ", yyAge=" + this.getYyAge() + ")";
    }
}

使用

public class Main {

    public static void main(String[] args) {
        Demo demo = new Demo();
        // setter方法
        demo.setXxName("lucky").setYyAge(20);
        System.out.println("demo = " + demo);
    }
}

prefix属性

该属性是一个字符串数组,当该数组有值时,表示忽略字段中对应的前缀,生成对应的 getter 和 setter 方法。

如果,我们把它的前缀加到 @Accessors 的属性值中,则可以像没有前缀那样,去调用字段的 getter和 setter 方法。

这里只是把原有属性的前缀给去掉

其他注解

@SneakyThrows

这个注解用在方法上,可以将方法中的代码用try-catch语句包裹起来,捕获异常并在catch中用Lombok.sneakyThrow(e)把异常抛出,可以使用@SneakyThrows(Exception.class)的形式指定抛出哪种异常

public class Demo {
    @SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF8");
    }
}

编译生成后:

public class Demo {
    public String utf8ToString(byte[] bytes) {
        try {
            return new String(bytes, "UTF8");
        } catch (UnsupportedEncodingException var3) {
            throw var3;
        }
    }
}

@Value

@Value注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法。

所以@Value更适合只读性更强的类,所以特殊情况下,还是可以使用的。

@Cleanup

@Cleanup能够自动释放资源; 和 try-with-resources的区别: try-with-resources和lombok的@Cleanup

这个注解用在局部变量上,可以保证此变量代表的资源会被自动关闭,默认是调用资源的close()方法。

如果该资源有其它关闭方法,可使用@Cleanup(“methodName”)来指定要调用的方法,就用输入输出流来举个例子吧:

@SneakyThrows(Exception.class)
public static void main(String[] args) {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[1024];
    while (true) {
        int r = in.read(b);
        if (r == -1) break;
        out.write(b, 0, r);
    }
}

编译后生成:

public static void main(String[] args) {
    try {
        FileInputStream in = new FileInputStream(args[0]);

        try {
            FileOutputStream out = new FileOutputStream(args[1]);

            try {
                byte[] b = new byte[1024];

                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();
            }

        }
    } catch (Exception var15) {
        throw var15;
    }
}

@NotNull

这个注解可以用在成员方法或者构造方法的参数上,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常。

//成员方法参数加上@NonNull注解
public String getName(@NonNull Person p){
    return p.getName();
}

编译生成后:

public String getName(@NonNull Person p){
    if(p == null){
        throw new NullPointerException("person");
    }
    return p.getName();
}

@Synchronized

作用于方法,可以替换 synchronized 关键字或 lock 锁

这个注解用在类方法或者实例方法上,效果和synchronized关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象

而@Synchronized得锁对象分别是私有静态final对象lock和私有final对象lock,当然,也可以自己指定锁对象

注意: 属性value指定锁对象,当锁对象不存在时,则编译不通过,默认为 “”

public class Demo {

    private Object obj;

    @Synchronized
    public static void hello() {
        System.out.println("world");
    }

    @Synchronized
    public int answerToLife() {
        return 42;
    }

    @Synchronized("obj")
    public void foo() {
        System.out.println("bar");
    }
}

编译后生成:

public class Demo {
    private static final Object $LOCK = new Object[0];
    private final Object $lock = new Object[0];
    private Object obj;

    public Demo() {
    }

    public static void hello() {
        synchronized($LOCK) {
            System.out.println("world");
        }
    }

    public int answerToLife() {
        synchronized(this.$lock) {
            return 42;
        }
    }

    public void foo() {
        synchronized(this.obj) {
            System.out.println("bar");
        }
    }
}

@Log、@Log4j、@Slf4j、@Log4j2、@CommonsLog、@XSlf4j等日志注解

相对日志进行了解的, 请参考我的博客 : 日志系列

这些注解都有topic属性:设置 getLogger(String name) 方法的参数

这些注解用在类上,可以省去从日志工厂生成日志对象这一步,直接进行日志记录。

具体注解根据日志工具的不同而不同,同时,可以在注解中使用topic来指定生成log对象时的类名。不同的日志注解总结如下(上面是注解,下面是实际作用):

@Log注解

默认是会生成java.util.logging.Logger对象, JUL

private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

使用JUL日志框架

@Log
public class LombokJULTest {
    /*
        日志入口程序
        java.util.logging.Logger
     */
     
    // @Log标注在JULTest类上,就表示自动生成了下面这行代码
    // Logger log = Logger.getLogger("com.lucky.jul.JULTest");
    @Test
    public void test01() {
        // 方式1
        log.info("输出info信息1");
        // 方式2
        log.log(Level.INFO, "输出info信息2");
    }
}

控制台输出:
八月 14, 2022 9:17:13 上午 com.lucky.jul.JULTest test01
信息: 输出info信息1
八月 14, 2022 9:17:13 上午 com.lucky.jul.JULTest test01
信息: 输出info信息2

编译后生成:

public class LombokJULTest {
    private static final Logger log = Logger.getLogger(LombokJULTest.class.getName());

    public LombokJULTest() {
    }

    @Test
    public void testLombokLog() {
        log.info("输出info信息1");
        log.log(Level.INFO, "输出info信息2");
    }
}

@Log4j注解

默认是会生成 org.apache.log4j.Logger 对象

private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

使用Log4j框架案例:

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

log4j配置文件 (resources下, log4j.properties文件)

log4j.rootLogger=trace,console,
#配置appender输出方式
log4j.appender.console=org.apache.log4j.ConsoleAppender
#配置输出的格式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.conversionPattern=[%-5p]%r %c%t%d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

@Log4j
public class LombokLog4jTest {

    // 使用Lombok的@Log4j注解, 相当于会自动生成下面这个logger对象
    // Logger log = Logger.getLogger(LombokLog4jTest.class);

    @Test
    public void testLombokLog4j() {
        // BasicConfigurator.configure(); // 默认指定了log4j的logger,输出位置,输出格式;不需要配置文件也可以打印日志

        // debug是默认的级别, 所以不会输出trace信息
        log.fatal("fatal信息");
        log.error("error信息");
        log.warn("warn信息");
        log.info("info信息");
        log.debug("debug信息");
        log.trace("trace信息");
    }
}

控制台输出:
[FATAL]0 com.lucky.log4j.LombokLog4jTestmain2022-08-14 11:02:45:720 fatal信息
[ERROR]2 com.lucky.log4j.LombokLog4jTestmain2022-08-14 11:02:45:722 error信息
[WARN ]2 com.lucky.log4j.LombokLog4jTestmain2022-08-14 11:02:45:722 warn信息
[INFO ]3 com.lucky.log4j.LombokLog4jTestmain2022-08-14 11:02:45:723 info信息

编译后生成代码:

public class LombokLog4jTest {
    private static final Logger log = Logger.getLogger(LombokLog4jTest.class);

    public LombokLog4jTest() {
    }

    @Test
    public void testLombokLog4j() {
        log.fatal("fatal信息");
        log.error("error信息");
        log.warn("warn信息");
        log.info("info信息");
        log.debug("debug信息");
        log.trace("trace信息");
    }
}

@Log4j2注解

前最优秀的Java日志框架, Log4j2也可以充当简单的日志门面来使用

private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

使用案例: (本次使用Log4j2充当日志门面,实现简单的日志打印)

<dependencies>
     <!-- log4j2日志门面 -->
      <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-api</artifactId>
          <version>2.12.1</version>
      </dependency>

      <!-- log4j2日志实现 -->
      <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-core</artifactId>
          <version>2.12.1</version>
      </dependency>

      <!-- 异步日志依赖 -->
      <dependency>
          <groupId>com.lmax</groupId>
          <artifactId>disruptor</artifactId>
          <version>3.3.7</version>
      </dependency>
</dependencies>

resources目录下, log4j2.xml

<?xml version="1.0" encoding="utf-8" ?>
<Configuration status="debug">
    <!-- 配置appender -->
    <Appenders>
        <Console name="consoleAppender" target="SYSTEM_ERR">
            <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"/>
        </Console>
    </Appenders>
    <!-- 配置logger -->
    <Loggers>
        <!-- 配置root logger -->
        <Root level="trace">
            <!-- 引用appender -->
            <AppenderRef ref="consoleAppender"/>
        </Root>
    </Loggers>
</Configuration>

import lombok.extern.log4j.Log4j2;
import org.junit.Test;

@Log4j2
public class LombokLog4j2Test {

    // @Log4j2会自动生成下面的Logger对象
    // Logger log = LogManager.getLogger(Log4j2Test.class);

    @Test
    public void lombokLog4jTest() {
        log.fatal("fatal信息");
        log.error("error信息");
        log.warn("warn信息");
        log.info("info信息");
        log.debug("debug信息");
        log.trace("trace信息");
    }
}

控制台输出:
[FATAL] 2022-08-14 11:43:31.845 com.lucky.Log4j2Test lombokLog4jTest 14 main fatal信息
[ERROR] 2022-08-14 11:43:31.849 com.lucky.Log4j2Test lombokLog4jTest 15 main error信息
[WARN ] 2022-08-14 11:43:31.849 com.lucky.Log4j2Test lombokLog4jTest 16 main warn信息
[INFO ] 2022-08-14 11:43:31.849 com.lucky.Log4j2Test lombokLog4jTest 17 main info信息
[DEBUG] 2022-08-14 11:43:31.850 com.lucky.Log4j2Test lombokLog4jTest 18 main debug信息
[TRACE] 2022-08-14 11:43:31.850 com.lucky.Log4j2Test lombokLog4jTest 19 main trace信息

编译后生成:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;

public class LombokLog4j2Test {
    private static final Logger log = LogManager.getLogger(LombokLog4j2Test.class);

    public LombokLog4j2Test() {
    }

    @Test
    public void lombokLog4jTest() {
        log.fatal("fatal信息");
        log.error("error信息");
        log.warn("warn信息");
        log.info("info信息");
        log.debug("debug信息");
        log.trace("trace信息");
    }
}

@Slf4j注解

Slf4j日志门面(Simple Logging Facade For Java) , Slf4j主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

使用案例: (Slf4j + Log4j2实现日志输出)

<!-- slf4j日志门面 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- log4j2适配器 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.12.1</version>
</dependency>

<!-- log4j2日志门面 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.12.1</version>
</dependency>

<!-- log4j2日志实现 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.12.1</version>
</dependency>

<!-- 异步日志依赖 -->
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.7</version>
</dependency>

resources目录下, log4j2.xml

<?xml version="1.0" encoding="utf-8" ?>
<Configuration status="debug">
    <!-- 配置appender -->
    <Appenders>
        <Console name="consoleAppender" target="SYSTEM_ERR">
            <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"/>
        </Console>
    </Appenders>
    <!-- 配置logger -->
    <Loggers>
        <!-- 配置root logger -->
        <Root level="trace">
            <!-- 引用appender -->
            <AppenderRef ref="consoleAppender"/>
        </Root>
    </Loggers>
</Configuration>

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

@Slf4j
public class LombokSlf4jTest {

    // @Slf4j会自动生成下面这个Logger对象
    // Logger log = LoggerFactory.getLogger(LombokSlf4jTest.class);

    @Test
    public void lombokSlf4jTest() {
        log.error("error信息");
        log.warn("warn信息");
        log.info("info信息");
        log.debug("debug信息");
        log.trace("trace信息");
    }
}

编译后生成:

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LombokSlf4jTest {
    private static final Logger log = LoggerFactory.getLogger(LombokSlf4jTest.class);

    public LombokSlf4jTest() {
    }

    @Test
    public void lombokSlf4jTest() {
        log.error("error信息");
        log.warn("warn信息");
        log.info("info信息");
        log.debug("debug信息");
        log.trace("trace信息");
    }
}

其他的Lombok日志注解, 自行了解咯

@CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@JBossLog
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

@Delegate

被@Delegate注释的属性,会把这个属性类型的公有非静态方法合到当前类

public class Person {

    public void personMsg() {
        System.out.println("Person.personMsg");
    }

    public String printName(String name) {
        return name;
    }

    private Integer printAge(Integer age) {
        return age;
    }

    public static void printOther() {
        System.out.println("Person.printOther");
    }
}

@Getter
@Setter
public class Demo {

    @Delegate
    private Person person;
}

编译后生成:

public class Demo {
    private Person person;

    public Demo() {
    }

    public Person getPerson() {
        return this.person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public void personMsg() {
        this.getPerson().personMsg();
    }

    public String printName(String name) {
        return this.getPerson().printName(name);
    }
}

使用:

public class Main {

    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.setPerson(new Person());
        demo.personMsg();
        System.out.println(demo.printName("lucky"));
    }
}

@Singular

使用 @Singular 注解一个集合字段(如果没有指定 value 属性值,那么集合字段名需要是复数形式),会生成添加元素方法向集合添加单个元素

只能配合@Builder注解使用, 该注解作用于字段和参数上, 一般用在集合属性和集合参数

使用:

public class Main {

    public static void main(String[] args) {
        Demo demo = Demo.builder().name("lucky")
                .num(1).num(2).num(3)
                .build();
        System.out.println("demo = " + demo);
    }
}

控制台输出:
demo = Demo(name=lucky, nums=[1, 2, 3])

lombok: 优秀blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/19167.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Type-C显示器是什么,Type-C显示器的5大优势

在显示器领域内&#xff0c;USB Type-C接口还处于发展阶段&#xff0c;目前已经在新推出的一些高端显示器和旗舰显示器中有配置。USB Type-C接口的出现&#xff0c;将会形成以显示器为核心的桌面解决方案&#xff0c;用户可以把任何笔记本、手机、平板等等的画面转移到一台大屏…

docker php安装redis扩展

有这么一个情况&#xff0c;我在docker中&#xff0c;安装了镜像&#xff0c;也启动了容器&#xff0c;容器有&#xff1a;nginx、mysql、redis、php 是一个基本的开发环境 容器启动成功&#xff0c;我们先连接一下&#xff0c;看看是否正常。 先保证这些都ok&#xff0c;我们…

数据可视化工具 - ECharts以及柱状图的编写

1 快速上手 引入echarts 插件文件到html页面中 <head><meta charset"utf-8"/><title>ECharts</title><!-- step1 引入刚刚下载的 ECharts 文件 --><script src"./echarts.js"></script> </head>准备一个…

一顿饭的事儿,搞懂了Linux5种IO模型

大家好&#xff0c;我是老三&#xff0c;人生有三大难题&#xff0c;事业、爱情&#xff0c;和 ——这顿吃什么&#xff01; 人在家中躺&#xff0c;肚子饿得响&#xff0c;又到了不得不吃的时候&#xff0c;这顿饭该怎么吃&#xff1f;吃什么呢&#xff1f; Linux里有五种I…

chatgpt搜索脚本

安装地址 https://greasyfork.org/zh-CN/scripts/459997 注意事项 &#xff01;&#xff01;注意&#xff1a;如果你在360相关浏览器上使用插件。360搜索将不会生效&#xff0c;因为已被浏览器禁用在so.com网址上使用。 &#xff01;&#xff01;尽量选择tampermonkey脚本管…

Datax的使用说明及入门操作案例演示

1.DataX DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS, dat…

第四十九章 Unity UI适配器组件

首先&#xff0c;我们介绍内容大小适配器 (Content Size Fitter)组件。 我们新建一个“SampleScene6.unity”场景&#xff0c;然后添加一个Text UI元素&#xff0c;让其居中显示&#xff0c;并且尺寸设置为50*30。 由于我们设置Text的尺寸在水平方向上面太小&#xff0c;也就是…

计算机毕业论文内容参考|基于神经网络的网络安全态势感知技术研究

文章目录 导文文章重点摘要前言绪论课题背景国内外现状与趋势课题内容相关技术与方法介绍技术分析技术设计技术实现总结与展望导文 基于神经网络的网络安全态势感知技术研究 文章重点 摘要 随着互联网的快速发展,网络攻击的频率和复杂度也在逐年增加。为了更好地保护信息系统…

【Python】【进阶篇】27、Django url标签详解

目录 27、Django url标签详解1. url标签基本使用2. 给定参数的动态url 27、Django url标签详解 在 Django 的模板语言中除了我们前面章节介绍过的 if 标签和 for 标签之外&#xff0c;还有许多我们时常用到标签&#xff0c;比如 url 标签。 1. url标签基本使用 Django 的模板…

4.6k Star,SpringBoot+Vue+App+硬件实现的智能家居系统,一套带走

今天&#xff0c;推荐一个智能家居系统项目。这是我目前见过的最好的智能家居系统项目&#xff0c;功能完整&#xff0c;代码结构清晰。值得推荐。 4.6k Star&#xff0c;SpringBootVueApp硬件实现的智能家居系统&#xff0c;一套带走 简介 FastBee是一个简单易用的物联网平…

【设计模式】责任链模式的介绍及其应用

责任链的介绍 责任链模式是一种对象的行为模式。在责任链模式里&#xff0c;很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递&#xff0c;直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求&a…

谷歌浏览器 | Chrome DevTools系统学习篇-Device Mode

大家好&#xff0c;文接上回谷歌浏览器 | Chrome DevTools系统学习篇-概述。所谓“工欲善其事&#xff0c;必先利其器”&#xff0c;我们进一步来熟悉谷歌开发者工具。今天分享的是Device Mode&#xff0c;使用设备模式来估算您的页面在移动设备上的外观和性能。 设备模式是 Ch…

QT多线程基础

文章目录 前言一、多线程概念介绍二、创建一个线程三、start和terminate函数四、如何不使用terminate函数终止线程总结 前言 本篇文章来讲解一下QT中的多线程使用方法。 其实线程这个概念对于我们来说并不陌生&#xff0c;main函数在多线程中一般就被称为主线程。 在QT中&am…

如何在IVD行业运用IPD?

IVD&#xff08;体外诊断&#xff0c;In Vitro Diagnostic&#xff09;是指对人体样本&#xff08;血液、体液、组织&#xff09;进行定性或定量的检测&#xff0c;进而判断疾病或机体功能的诊断方法。IVD目前已经成为疾病预防、诊断治疗必不可少的医学手段&#xff0c;约80%左…

这才是 玩转Github 的正确姿势

这才是 玩转Github 的正确姿势 GitHub各位应该都很熟悉了&#xff0c;全球最大的开源社区&#xff0c;也是全球最大的同性交友网站~~&#xff0c;但是大部分同学使用GitHub应该就是通过别人的开源链接&#xff0c;点进去下载对应的项目&#xff0c;而真正使用Github来查找开源…

camunda的Java委托如何使用

一、camunda的Java委托有什么用途 在Camunda中&#xff0c;Java委托是一种用于在流程执行期间执行自定义逻辑的Java类。使用Java委托&#xff0c;您可以在流程执行期间通过Java代码实现各种复杂的业务逻辑。 以下是一些使用Java委托的常见用途&#xff1a; 1、计算值&#x…

有什么好用的云渲染?

在CG制作流程中&#xff0c;离线渲染一直是必要且耗时的环节。你的场景越复杂&#xff0c;渲染出现问题的可能性就越大&#xff0c;尤其是当你独自工作&#xff0c;没有人给你建议的时候&#xff0c;灯光、模型、场景任何一个环节渲染时出现问题都可能让你焦头烂额&#xff0c;…

基于Kubernetes集群构建大中型企业CICD应用平台(2)--code阶段工具gitlab安装

这里我们为gitlab服务器准备一台虚拟机&#xff1a;192.168.19.6-gitlab服务器 在code阶段&#xff0c;我们需要将不同版本的代码存储到一个仓库中&#xff0c;常见的版本控制工具就是SVN或者Git&#xff0c;这里我们采用Git作为版本控制工具&#xff0c;GitLab作为远程仓库。…

5 创建映射

5 映射 上边章节安装了ik分词器&#xff0c;如果在索引和搜索时去使用ik分词器呢&#xff1f;如何指定其它类型的field&#xff0c;比如日期类型、数 值类型等。 本章节学习各种映射类型及映射维护方法。 5.1 映射维护方法 1、查询所有索引的映射&#xff1a; GET&#xf…

Linux性能监控与调优工具

Linux性能监控与调优工具 文章目录 Linux性能监控与调优工具1.使用top、 vmstat、 iostat、 sysctl等常用工具2.使用高级分析手段&#xff0c; 如OProfile、 gprof4.使用LTP进行压力测试5.使用Benchmark评估系统 除了保证程序的正确性以外&#xff0c; 在项目开发中往往还关心性…