Lombok 注解及实例大全

Lombok是一个Java库,通过注解自动处理getter、setter、equals、hashCode、toString等方法,减少样板代码。它还提供了@NonNull、@Cleanup、@Builder、@Synchronized等实用注解,简化资源管理、非空检查和构建过程。@Data、@NoArgsConstructor、@AllArgsConstructor、@RequiredArgsConstructor等注解则帮助生成构造器。此外,@Log系列注解简化了日志记录。Lombok使得代码更加简洁,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Project Lombok是一个java库,它可以自动插入到编辑器和构建工具中,为Java增添趣味。 永远不要再编写另一个getter或equals方法,只要有一个注释,你的类就有一个功能齐全的构建器,自动化你的日志变量,等等。

val

用在局部变量前面,相当于将变量声明为 final

val map = new HashMap<String, String>();
// 相当于
final Map<String, String> map = new HashMap<>();

但是这个功能不能再 IDEA 中正确运行

@NonNull

给 属性、方法参数 增加这个注解会自动在方法内对该参数进行是否为空的校验。

形参前加上@NonNull,当传入参数为null时,会抛出 NPE(NullPointerException)

不加@NonNull,会打印结果null,不会抛异常

修饰属性:

public class UserLombok {
    private Long id;

    private String name;

    @NonNull
    private String school;
}

修饰方法参数:

public void testNonNull(@NonNull String name) {
    System.out.println(name);
}

// 相当于
public void testNonNull(String name) {
    if (name != null) {
        System.out.println(name);
    } else {
        throw new NullPointerException("null");
    }
}

@Cleanup

自动管理资源,用在局部变量之前,在当前变量范围内即将执行完毕退出之前会自动清理资源,自动生成 try-finally 这样的代码来关闭流

public static void main(String[] args) {
    try {
        @Cleanup InputStream inputStream = new FileInputStream(args[0]);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    
    // 相当于
    InputStream inputStream = null;
    try {
        inputStream = new FileInputStream(args[0]);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

@Getter/@Setter

标注在类上

标注在类上,表示针对该类中所有的非静态字段进行 get、set 方法自动生成。

标注在字段上

标注在字段上,用于自动生成 get、set 方法,boolean 类型字段 get 方法为 isXXX() 方法。

生成的 get、set 方法默认情况下都是 public 的,但也可以手动指定以下四种范围:

  • AccessLevel.PUBLIC
  • AccessLevel.MODULE
  • AccessLevel.PROTECTED
  • AccessLevel.PACKAGE
  • AccessLevel.PRIVATE
@Data
public class User {

    private String name;

    @Setter(AccessLevel.PRIVATE)  // 生成的Setter方法是private的
    private String address;

    @Setter @Getter(AccessLevel.PRIVATE)  // 生成的Setter和Getter方法是private的
    private String phone;
}

如果指定某个字段的 AccessLevel = AccessLevel.NONE,则可以使该生成动作失效,此时可以手动实现get、set方法,AccessLevel.NONE 可以应用于在某些方法中有一些自定义逻辑的情况下。

@Getter
@Setter
public class User {
    private String name;
    
    private Integer age;

    @Getter(value = AccessLevel.NONE)
    private boolean child;

    public boolean isChild() {
        if(age < 12) {
            return true;
        }
        return false;
    }
}

@ToString

用在类上可以自动覆写 toString 方法,当然还可以加其他参数

例如 @ToString(exclude=”id”) 排除 id 属性,@ToString(exclude={"id", "name"})排除多个属性

或者 @ToString(callSuper=true, includeFieldNames=true) 调用父类的 toString 方法,包含所有属性

@ToString(exclude = "id", callSuper = true, includeFieldNames = true)
publicclass LombokDemo {
    private int id;
    private String name;
    private int age;
    public static void main(String[] args) {
        // 输出 LombokDemo(super=LombokDemo@48524010, name=null, age=0)
        System.out.println(new LombokDemo());
    }
}

@EqualsAndHashCode

用在类上自动生成 equals(Object other)hashcode() 方法,包括所有非静态变量和非 transient 的变量

@EqualsAndHashCode(exclude = {"id", "name"}, callSuper = false)
public class User {
    private int id;
    private String name;
}

为什么要重写hashcode和equals方法

为什么只有一个整体的 @EqualsAndHashCode 注解,而不是分开的两个 @Equals@HashCode

  • 在 Java 中有规定,当两个对象 equals 时,他们的 hashcode 一定要相同,反之,当 hashcode 相同时,对象不一定 equals。所以 equals 和 hashcode 要一起实现,免得发生违反 Java 规定的情形发生

@Data

lombok 项目的产生就是为了省去我们手动创建getter和setter等基本方法的麻烦,它能够在我们编译源码的时候自动帮我们生成getter和setter等方法。即它最终能够达到的效果是:在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法

注意:@EqualsAndHashCode注解与@ToString注解默认情况下是忽略父类的成员变量的。

在类继承的情况时应注意@Data注解不会涉父类的成员的坑,需要加callSuper = true的参数。

@Data 是整合包,只要加了 @Data 这个注解,等于同时加了以下注解

  • @Getter/@Setter
  • @ToString
  • @EqualsAndHashCode
  • @RequiredArgsConstructor

@NoArgsConstructor

@AllArgsConstructor

@RequiredArgsConstructor

@NoArgsConstructor

用在类上,自动生成无参构造器

@AllArgsConstructor

用在类上,自动生成使用所有参数的构造器

@RequiredArgsConstructor

用在类上,生成一个包含 “特定参数” 的构造器,特定参数指的是所有被 final 修饰的变量

把所有 被@NonNull 或者 final 修饰的属性作为参数的构造函数

@RequiredArgsConstructor
public class UserLombok {
    private Long id;

    private String name;

    private String phoneNo;

    private final String address;

    @NonNull
    private String school;
}

则会生成一个包含address和school的构造函数

指定 staticName=“of” 参数

如果指定 staticName=“of” 参数,同时还会生成一个返回类对象的静态工厂方法,比使用构造函数方便很多

@Slf4j
@RequiredArgsConstructor(staticName="of")
@AllArgsConstructor(staticName="of")
@ToString
public class UserLombok {

    private Long id;

    private String name;

    private String phoneNo;

    private final String address;

    private String school;
    
    @Test
    public void test() {
        UserLombok userLombok1 = UserLombok.of("cc");
        UserLombok userLombok2 = UserLombok.of(2L, "hory", "155", "sh", "cc");

        log.info("userLombok toString:{}", userLombok1.toString());
        // userLombok toString:UserLombok(id=null, name=null, phoneNo=null, address=cc, school=null)
        
        log.info("userLombok toString:{}", userLombok2.toString());
        // userLombok toString:UserLombok(id=2, name=hory, phoneNo=155, address=sh, school=cc)
    }
}

注意:

  • 当我们没有指定构造器时,Java 编译器会自动生成一个没有任何参数的构造器,但是如果我们自己写了构造器之后,Java 就不会自动帮我们补上那个无参数的构造器了。
  • 然而很多地方(像是 Spring Data JPA),会需要每个类都一定要有一个无参数的构造器,所以在加上 @AllArgsConstructor 时,一定要补上 @NoArgsConstrcutor
  • @AllArgsConstructor@NoArgsConstrcutor是可以共用的

@Value

也是整合包,但是它会把所有的变量都设成 final 的,其他的就跟 @Data 一样,等于同时加了以下注解

  • @Getter(注意没有setter)
  • @ToString
  • @EqualsAndHashCode
  • @RequiredArgsConstructor

@Data 适合用在 POJO 或 DTO 上,而这个 @Value 注解,则是适合加在值不希望被改变的类上,像是某个类的值当创建后就不希望被更改,只希望我们读它而已,就适合加上 @Value 注解,也就是 @Value for immutable class

注意:此 lombok 的注解 @Value 和另一个 Spring 的注解 @Value 撞名,在 import 时不要 import 错了

@Builder

自动生成流式 set 值写法,从此之后再也不用写一堆 setter 了.

public class User {
    private Integer id;
    private String name;
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

public static void main(String[] args) {
    User user = new User();
    user.setId(1);
    user.setName("John");
}

等同于下面的写法

@Builder
public class User {
    private Integer id;
    private String name;
}

public static void main(String[] args) {
    User user = User.builder().id(1).name("John").build();
}

注意:虽然只要加上 @Builder 注解,就能够用流式写法快速设定对象的值,但 setter 还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对它们取值/赋值。

所以通常是 @Data 和 @Builder 会一起用在同个类上,既方便我们流式写代码,也方便框架做事。

@SneakyThrows

https://www.cnblogs.com/acmaner/p/13967688.html

自动抛受检异常,而无需显式在方法上使用 throws 语句

publicclass ThrowsTest {
    
    @SneakyThrows()
    public void read() {
        InputStream inputStream = new FileInputStream("");
    }
    @SneakyThrows
    public void write() {
        throw new UnsupportedEncodingException();
    }
    
    // 相当于
    public void read() throws FileNotFoundException {
        InputStream inputStream = new FileInputStream("");
    }
    public void write() throws UnsupportedEncodingException {
        throw new UnsupportedEncodingException();
    }
}

@Synchronized

用在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性 或LOCK

而 Java 中的 synchronized 关键字锁对象是 this,锁在 this 或者自己的类对象上存在副作用,就是你不能阻止非受控代码去锁 this 或者类对象,这可能会导致竞争条件或者其它线程错误

public class SynchronizedDemo {
    @Synchronized
    public static void hello() {
        System.out.println("world");
    }
    
    // 相当于
    private static final Object $LOCK = new Object[0];
    public static void hello() {
        synchronized ($LOCK) {
            System.out.println("world");
        }
    }
}

@Getter(lazy=true)

可以替代经典的 Double Check Lock 样板代码

public class GetterLazyExample {
    
    @Getter(lazy = true)
    private final double[] cached = expensive();
    
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

相当于

import java.util.concurrent.atomic.AtomicReference;

public class GetterLazyExample {
    
    private final AtomicReference<java.lang.Object> cached = new AtomicReference<>();
    
    public double[] getCached() {
        java.lang.Object value = this.cached.get();
        if (value == null) {
            synchronized (this.cached) {
                value = this.cached.get();
                if (value == null) {
                    final double[] actualValue = expensive();
                    value = actualValue == null ? this.cached : actualValue;
                    this.cached.set(value);
                }
            }
        }
        return (double[]) (value == this.cached ? null : value);
    }
    
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

@Log

@Log:根据不同的注解生成不同类型的 log 对象,但是实例名称都是 log,有六种可选实现类

  • @CommonsLog Creates log = org.apache.commons.logging.LogFactory.getLog(LogExample.class)
  • @Log Creates log = java.util.logging.Logger.getLogger(LogExample.class.getName())
  • @Log4j Creates log = org.apache.log4j.Logger.getLogger(LogExample.class)
  • @Log4j2 Creates log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class)
  • @Slf4j Creates log = org.slf4j.LoggerFactory.getLogger(LogExample.class)
  • @XSlf4j Creates log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class)

@Slf4j

自动生成该类的 log 静态常量,要打日志就可以直接打,不用再手动 new log 静态常量了

public class User {
    private static final Logger log = LoggerFactory.getLogger(User.class);
    
    public static void main(String[] args) {
    	log.info("hello");
	}
}

等同于下面的写法

@Slf4j
public class User {
    public static void main(String[] args) {
    	log.info("hello");
	}
}

除了 @Slf4j 之外,lombok 也提供其他日志框架的变种注解可以用,像是 @Log、@Log4j…等,它们都是帮我们创建一个静态常量 log,只是使用的库不一样而已.

@Log

import java.util.logging.Logger;

@Log
private static final Logger log = Logger.getLogger(LogExample.class.getName());

@Log4j

import org.apache.log4j.Logger;

@Log4j
private static final Logger log = Logger.getLogger(LogExample.class);

log 系列注解最常用的就是 @Slf4j,SpringBoot 默认支持的就是 slf4j + logback 的日志框架,所以也不用再多做啥设定,直接就可以用在 SpringBoot project上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值