lombok的学习
基本概念
- Lombok项目其实就是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能。以后你只需要一些简单的注解,就可以再也不用在类中反复去写get、equals等方法。
- 使用lombok可以简化开发的代码量,减少书写的set、get方法以及一些基本的校验
参考
- 官方注解文档:https://projectlombok.org/features/
- https://projectlombok.org/features/experimental/
- 官方API文档:https://projectlombok.org/api/
@NonNull
- 可以使用在类的构造方法的参数上,或者属性的set方法中的参数上
属性set方法上:
public void setName(@NonNull String name) {
this.name = name;
}
// 相当于
public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
this.name = name;
}
构造方法上
public Entity1(@NonNull String attribute1,@NonNull String attribute2) throws Exception {
this.attribute1 = attribute1;
this.attribute2 = attribute2;
}
// 相当于
public Entity1(String attribute1,@NonNull String attribute2) throws Exception {
if (attribute2 == null) {
throw new NullPointerException("attribute2 is marked @NonNull but is null");
this.attribute1 = attribute1;
this.attribute2 = attribute2;
}
@Setter和@Getter
- 在类中的属性上使用,可以当成属性存在set和get方法
- 这两个注解可以通过AccessLevel来设置访问权限
public class Entity2 {
@Setter
@Getter
private String attribute1;
@Setter(AccessLevel.PRIVATE)
private String attribute2;
}
@Cleanup
- 这个注解用在变量前面,可以保证此变量对应的资源回自动关闭,默认调用资源的close()方法
- 如果该资源有其他关闭方法,可以使用@Cleanup(“methondName”)来指定要调用的方法
import lombok.Cleanup;
import java.io.*;
public class test3 {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = methond1();
System.out.println(fileInputStream.available());
}
private static FileInputStream methond1() throws IOException {
@Cleanup
FileInputStream writer = new FileInputStream("E:\\test.txt");
System.out.println(writer.available());
return writer;
}
}
// 结果:
// 12
// Exception in thread "main" java.io.IOException: Stream Closed
@ToString
- 在类名上面使用,可以标识类已经重写了toString方法
@EqualsAndHashCode
- 在类名上面使用,可以标识类已经重写了equals方法和HashCode方法
@NoArgsConstructor、@RequiredArgsConstructor和@AllArgsConstructor
- 这三个注解用于自动生成构造方法
- @NoArgsConstructor
- 用于生成一个无参的默认构造方法。它可以自动为类生成一个无参的构造方法,无需手动编写。
- @RequiredArgsConstructor
- 用于生成构造方法,只包含带有final或@NonNull注解的成员变量作为参数。它可以自动为这些成员变量生成对应的构造方法。
- @AllArgsConstructor
- 用于生成一个包含所有非静态成员变量的构造方法。它可以自动为类生成一个包含所有成员变量的构造方法。
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class MyClass {
private String name;
private int age;
// 其他成员和方法
}
@Data
- 注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
@Value
- 注解在类上,会为类的所有属性自动生成getter、equals、canEqual、hashCode、toString方法
- 由于没有生成setter方法,所以一旦对象创建后,其字段值就无法修改。
- 与@Date的区别:
- 会把所有成员变量默认定义为private final修饰,并且不会生成set方法。
- @Data 适用于需要可变性的类,它会生成 getter 和 setter 方法;@Value 适用于不可变性的类,它只生成 getter 方法,没有 setter 方法。这对于保证对象的不可变性是有益的。
@SneakyThrows
- 这个注解用在方法上,可以将方法中的代码用try-catch语句包裹起来
- 捕获异常并在catch中用Lombok.sneakyThrow(e)把异常抛出
- 可以使用@SneakyThrows(Exception.class)的形式指定抛出哪种异常
public class SneakyThrows implements Runnable {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
@SneakyThrows
public void run() {
throw new Throwable();
}
}
// 相当于:
public class SneakyThrows implements Runnable {
public String utf8ToString(byte[] bytes) {
try{
return new String(bytes, "UTF-8");
}catch(UnsupportedEncodingException uee){
throw Lombok.sneakyThrow(uee);
}
}
public void run() {
try{
throw new Throwable();
}catch(Throwable t){
throw Lombok.sneakyThrow(t);
}
}
}
@Synchronized
- @Synchronized这个注解用在类方法或者实例方法上,效果和synchronized关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象,而@Synchronized得锁对象分别是私有静态final对象LOCK和私有final对象lock,当然,也可以自己指定锁对象
public class Synchronized {
private final Object readLock = new Object();
@Synchronized
public static void hello() {
System.out.println("world");
}
@Synchronized
public int answerToLife() {
return 42;
}
@Synchronized("readLock")
public void foo() {
System.out.println("bar");
}
}
相当于:
public class Synchronized {
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object();
public static void hello() {
synchronized($LOCK) {
System.out.println("world");
}
}
public int answerToLife() {
synchronized($lock) {
return 42;
}
}
public void foo() {
synchronized(readLock) {
System.out.println("bar");
}
}
}
@Log
- 这个注解用在类上,可以省去从日志工厂生成日志对象这一步,直接进行日志记录,具体注解根据日志工具的不同而不同,同时,可以在注解中使用topic来指定生成log对象时的类名。不同的日志注解总结如下(上面是注解,下面是实际作用):
@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);
@Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ExampleClass {
public void doSomething() {
log.info("This is an info log message.");
log.error("This is an error log message.");
}
}
注解的缺点
- 高入侵性
- Lombok插件的使用,要求开发者一定要在IDE中安装对应的插件。不仅自己要安装,任何和你协同开发的人都要安装。如果有谁未安装插件的话,使用IDE打开一个基于Lombok的项目的话会提示找不到方法等错误,导致项目编译失败。更重要的是,如果我们定义的一个jar包中使用了Lombok,那么就要求所有依赖这个jar包的所有应用都必须安装插件,这种侵入性是很高的。
- 代码可调试性降低
- Lombok确实可以帮忙减少很多代码,因为Lombok会帮忙自动生成很多代码。但是,这些代码是要在编译阶段才会生成的,所以在开发的过程中,其实很多代码其实是缺失的。这就给代码调试带来一定的问题,我们想要知道某个类中的某个属性的getter方法都被哪些类引用的话,就没那么简单了。
- 影响版本升级
- Lombok对于代码有很强的侵入性,就可能带来一个比较大的问题,那就是会影响我们对JDK的升级。按照如今JDK的升级频率,每半年都会推出一个新的版本,但是Lombok作为一个第三方工具,并且是由开源团队维护的,那么他的迭代速度是无法保证的。所以,如果我们需要升级到某个新版本的JDK的时候,若其中的特性在Lombok中不支持的话就会受到影响。还有一个可能带来的问题,就是Lombok自身的升级也会受到限制。因为一个应用可能依赖了多个jar包,而每个jar包可能又要依赖不同版本的Lombok,这就导致在应用中需要做版本仲裁,而我们知道,jar包版本仲裁是没那么容易的,而且发生问题的概率也很高。
- 可能会破坏封装性
- 一般构建一个类并不会直接生成所有字段的set和get方法,如果使用了lombok中的注解类似于@Data,就会自动将所有适合的字段都生成对应的set和get,就可能会破坏封装性。
- Lombok虽好,但缺点也不少,如果你在公司团队开发中被强X了,你就只能使用,如果新项目开发,能不用就尽量别用了,否则坑也不少的!