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

news2024/11/24 10:33:16

文章目录

  • 介绍
  • 引入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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无需繁琐手工操作,如何利用Web自动化测试元素定位做到快速高效的测试?

1、什么是Web自动化测试元素定位&#xff1f; 在Web自动化测试中&#xff0c;元素定位是非常重要的环节。因为我们需要找到需要进行操作的页面元素&#xff0c;例如按钮、输入框、下拉菜单等等。元素定位可以帮助我们在自动化测试中对这些元素进行操作&#xff0c;如点击、输入…

老域名查询工具- 在线域名批量查询工具

域名批量查询工具 域名批量查询工具是一种帮助用户快速查询多个域名信息的工具&#xff0c;通常能够自动扫描一组域名的WHOIS信息、DNS、IP地址、服务器等各种信息&#xff0c;并提供快速的结果反馈。 以下是域名批量查询工具主要的优点&#xff1a; 提高工作效率&#xff1a…

培训出来包装三年经验拿21K,入职8天就被裁了....

最近翻了一些网站的招聘信息&#xff0c;把一线大厂和大型互联网公司看了个遍&#xff0c;发现市场还是挺火热的&#xff0c;虽说铜三铁四&#xff0c;但是软件测试岗位并没有削减多少&#xff0c;建议大家有空还是多关注和多投简历&#xff0c;不要闭门造车&#xff0c;错过好…

腾讯云面试题-重复的字符串+设计测试用例

原题出自&#xff1a;https://leetcode.cn/problems/repeated-substring-pattern/ 题目&#xff1a; 题解&#xff1a; 1、字符串长度为空&#xff0c;则返回false。 2、字符串长度为1&#xff0c;则为true&#xff0c;是由子串构成的。 3、字符串长度为2&#xff0c;判断首…

c++模板 理解(图、文、代码)

嗯&#xff0c;又是发个重点&#xff0c;拿出来单独做笔记 本文有参考以下博文&#xff1a; 1、C template \ auto_c template auto_rainbow_lucky0106的博客-CSDN博客 2、C 中的 const & &#xff08;常引用&#xff09;参数 - 知乎 3、C template \ auto_c template …

一文读懂国内首本《牛客2023金融科技校园招聘白皮书》

金融科技人才作为金融数字化转型的关键支撑&#xff0c;但当下金融科技人才培养体系尚未形成&#xff0c;优秀的金融科技人才供不应求&#xff0c;目前存在严重的人才供给问题。 据调研数据统计&#xff0c;96.8%的金融机构存在金融科技人才缺口&#xff0c;54.8%的机构认为新…

PDU配电单元推荐——同为科技(TOWE)自接线工程安全机柜PDU

随着信息化、数字化互联网技术在各行各业的迅速发展&#xff0c;符合现代化需求的机房建设尤为重要&#xff0c;其背后蕴藏着广阔的经济效益与市场前景。现代机房具备先进性、实用性、合理性、拓展性、精细化等特点&#xff0c;除了核心的计算机系统要实现安全可靠的平稳运行外…

UNIX中的文件属性和打开目录函数 lstat、opendir、readdir 5.13

文件属性获取与修改相关的操作函数 stat()fstat()/Istat() 文件类型 设置用户ID和设置组ID 文件存取许可权 新文件和目录的所有权 文件长度 文件截短. 文件的时间 打开目录 读取目录项 以下三个函数可以获取文件/目录的属性信息: #include <unistd.h> #include <sy…

小黑子—多媒体技术与运用基础知识四:计算机动画与视频处理技术

多媒体技术与运用4.0 多媒体系列第四章1. 计算机动态视觉媒体1.1 动态视觉媒体产生原理1.2 动态视频文件特点1.3 技术参数1.4 动画与视频的异同 2. 计算机动画的基础2.1 计算机动画的类型2.1.1 从动画生成机制划分2.1.2 从画面透视效果划分2.1.3 从画面形成规则和制作方法划分2…

PaLM 2全面反超反超GPT-4,谷歌官宣AI重构搜索,朝着ChatGPT微软开炮

来源 | 量子位 | 公众号 QbitAI 万众瞩目&#xff0c;谷歌的反击来了。 现在&#xff0c;谷歌搜索终于要加入AI对话功能了&#xff0c;排队通道已经开放。 当然这还只是第一步。 大的还在后面&#xff1a; 全新大语言模型PaLM 2正式亮相&#xff0c;谷歌声称它在部分任务超…

IT行业项目管理软件,你知道多少?

IT行业项目管理软件&#xff0c;主要得看用来管理的是软件研发还是做IT运维。如果是做软件研发&#xff0c;那还得看项目经理是用什么思路&#xff0c;是传统的瀑布式方法还是敏捷的方法或者是混合的方法。 如果用来管理的是IT运维工作&#xff0c;那么很多通用型的项目管理软件…

微服架构基础设施环境平台搭建 -(三)Docker+Kubernetes集群搭建

微服架构基础设施环境平台搭建 -&#xff08;三&#xff09;DockerKubernetes集群搭建 通过采用微服相关架构构建一套以KubernetesDocker为自动化运维基础平台&#xff0c;以微服务为服务中心&#xff0c;在此基础之上构建业务中台&#xff0c;并通过Jekins自动构建、编译、测试…

【python/request/HTMLTestRunner/unittest】接口自动化测试框架

正在调研使用python进行自动化测试&#xff0c;在网上发现一篇比较好的博文&#xff0c;作者使用的是python3&#xff0c;但目前自己使用的是python2&#xff0c;先转载下&#xff0c;后续再进行调试完善&#xff1b; 摘要: python requests实现的接口自动化框架详细教程 前…

VMware Aria Operations for Networks 6.10 - 网络和应用监控工具

VMware Aria Operations for Networks 6.10 - 网络和应用监控工具 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-aria-operations-for-networks/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org VMware Aria Oper…

Goby 漏洞更新 |WordPress Welcart e-Commerce 插件 content-log.php 文件 logfile 参数文件读取漏洞

漏洞名称&#xff1a;WordPress Welcart e-Commerce 插件 content-log.php 文件 logfile 参数文件读取漏洞 English Name&#xff1a;WordPress plugin Welcart e-Commerce content-log.php logfile File Read Vulnerability CVSS core: 9.8 影响资产数&#xff1a;5453 漏…

【操作系统】《2023 南京大学 “操作系统:设计与实现” (蒋炎岩)》- 知识点目录

《2023 南京大学 “操作系统&#xff1a;设计与实现” (蒋炎岩)》 1. 操作系统概述 (操作系统的历史&#xff1b;学习建议) [南京大学2023操作系统-P1] 1.1 Z3库&#xff1a;解决逻辑定理证明问题 Z3是由微软研究院开发的一个高效的定理证明器&#xff0c;用于解决逻辑定理证…

日撸 Java 三百行day50

文章目录 说明day50 小结1.比较分析各种查找算法.2.比较分析各种排序算法3.描述各种排序算法的特点和基本思想4.设计一个自己的 Hash 函数和一个冲突解决机制 说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己…

利用PostgreSQL的存储过程为多个库表增加固定字段

曾经只会增删改查和内置函数的SQL使用&#xff0c;第一次发现原来自定义函数/存储过程还是非常可以提高效率的。 背景需求&#xff1a; 需要为某个schema下的表追加字段。 原始手段&#xff1a;为每个表生成插入字段的SQL&#xff0c;执行&#xff0c;要粘贴好多遍表名 / 手…

【K8S系列】快速初始化⼀个最⼩集群

序言 走得最慢的人&#xff0c;只要不丧失目标&#xff0c;也比漫无目的地徘徊的人走得快。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级重要蓝色&#xff1a;用来标记二级重要 希望这篇文章能让你不仅有…

华为OD机试真题 Java 实现【贪心的商人】【2023Q1 100分】

一、题目描述 商人经营一家店铺&#xff0c;有number种商品&#xff0c;由于仓库限制每件商品的最大持有数量是item[index]&#xff0c;每种商品的价格在每天是item_price[item_index][day]&#xff0c;通过对商品的买进和卖出获取利润&#xff0c;请给出商人在days天内能获取…