懒人必备插件!本质是个Java库,主要能够简化pojo层的一些无脑操作,如:对象的构造函数、 equals()方法,属性的 get()/set()方法等等。

项目引入

现在SpringBoot创建时可以自动勾选Lombok了,手动的话需要两点:
1.在pom.xml中引入Lombok依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

2.在Settings——Plugins下载Lombok Plugin


@Data

@Data整合了以下五个:

  • @Getter/@Setter:可以在需要的属性上打上注解,通过AccessLevel.MODULE/PROTECTED/PRIVATE/PACKAGE/PUBLIC(默认)设置方法权限;也可以直接打在类上,通过 AccessLevel.NONE手动禁止生成get或set方法
public class Student {
    @Getter
    @Setter
    private int stuno;
    @Getter
    @Setter
    private String stuname;
    @Getter(AccessLevel.PRIVATE)
    private int cardid;
}
---
@Getter @Setter
public class Student {
    private int stuno;
    private String stuname;
    @Setter(AccessLevel.NONE)
    private int cardid;
}
  • @ToString:默认生成所有字段。可以用exclude属性禁止在 ToString方法中使用某字段,而用of属性指定需要使用的字段。
@ToString(of = {"stuno","stuname"},exclude = {"cardid"})
//只打印stuno和stuname两个属性,Student(stuno=1, stuname=zs)
public class Student {
    private int stuno;
    private String stuname;
    private int cardid;
}
  • @EqualsAndHashCode:自动生成equals(Object other)hashcode()方法,包括所有非静态属性和非 transient 的属性,同样该注解也可以通过 exclude 属性排除某些字段,of 属性指定某些字段,也可以通过 callSuper 属性在重写的方法中使用父类的字段。一般直接使用就行了。
    编译后的代码如下:
public boolean equals(final Object o) {
    if (o == this) {
        return true;
    } else if (!(o instanceof Student)) {
        return false;
    } else {
        Student other = (Student)o;
        if (!other.canEqual(this)) {
            return false;
        } else {
            label39: {
                Object this$stuno = this.getStuno();
                Object other$stuno = other.getStuno();
                if (this$stuno == null) {
                    if (other$stuno == null) {
                        break label39;
                    }
                } else if (this$stuno.equals(other$stuno)) {
                    break label39;
                }

                return false;
            }

            Object this$stuname = this.getStuname();
            Object other$stuname = other.getStuname();
            if (this$stuname == null) {
                if (other$stuname != null) {
                    return false;
                }
            } else if (!this$stuname.equals(other$stuname)) {
                return false;
            }

            if (this.getCardid() != other.getCardid()) {
                return false;
            } else {
                return true;
            }
        }
    }
}

protected boolean canEqual(final Object other) {
    return other instanceof Student;
}

public int hashCode() {
    int PRIME = true;
    int result = 1;
    Object $stuno = this.getStuno();
    int result = result * 59 + ($stuno == null ? 43 : $stuno.hashCode());
    Object $stuname = this.getStuname();
    result = result * 59 + ($stuname == null ? 43 : $stuname.hashCode());
    result = result * 59 + this.getCardid();
    return result;
}

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

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

  • @RequireArgsConstructor:改注解生成有参数构造器时只会包含有 final 和 @NonNull 标识的 field。
    注意:当有final字段存在时,会与下文无参构造@NoArgsConstructor产生冲突。
@RequiredArgsConstructor
public class Student {
    @NonNull
    private int stuno;
    private final String stuname;
    private int cardid;
}

---相当于---

public class Student {
    @NonNull
    private Integer stuno;
    private final String stuname;
    private int cardid;

    public Student(@NonNull final Integer stuno, final String stuname) {
        if (stuno == null) {
            throw new NullPointerException("stuno is marked non-null but is null");
        } else {
            this.stuno = stuno;
            this.stuname = stuname;
        }
    }
}

注意:
  如果使用 @Data 注解的类,继承成了其它父类的属性,最好额外添加 @ToString(callSuper = true)@EqualsAndHashCode(callSuper = true) 注解。
  因为默认情况下,@Data 注解不会处理父类的属性。所以需要我们通过 callSuper = true 属性,声明需要调用父类对应的方法。
  这个情况非常常见,例如说在实体类中,我们可能会声明一个抽象父类 AbstractEntity,而该类里有一个 id 编号属性。


@NonNull

打在方法或构造器的参数上或属性上,如上文所展示的,主要是用来判空。

public class Student {
    @NonNull
    private Integer stuno;
    private final String stuname;
    private int cardid;
}

---

@RequestMapping("/deleteByStuno")
public void deleteByStuno(@NonNull String stuno){
    studentService.deleteByStuno(stuno);
}

@NoArgsConstructor、@RequiredArgsConstructor、@AllArgsConstructor

@NoArgsConstructor:无参构造
@RequiredArgsConstructor:指定参数构造,具体详见上文@Data
@AllArgsConstructor:全参构造

从编译文件可看出:指定参数构造和全参构造的方法会自动为每个属性添加final属性。


@Builder

优雅的new一个对象,本质是用设计模式中的建造者模式创建对象。
链式调用确实优雅了很多起码指针不需要移动。

@ToString
@Builder
public class Student {
    private Integer stuno;
    private String stuname;
    private int cardid;
}

@RequestMapping("/stuToString")
@ResponseBody
public void stuToString(){
    Student student = Student.builder().stuno(1).stuname("zs").cardid(233).build();
    System.out.println(student.toString());
}

Student(stuno=1, stuname=zs, cardid=233)

@Log

省略了定义静态常量Logger的写法,直接在类上加@Log即可实现:
private static final Logger log = Logger.getLogger(XXX.class.getName());
当然也有很多中日志选择:
@CommonLog@Log@Log4j@Log4j2Slf4j等等。

@Log
@Controller
public class StudentController {
    @Autowired
    private StudentService studentService;

    @RequestMapping("/stuToString")
    @ResponseBody
    public void stuToString(){
        log.info("this is log...");
        Student student = Student.builder().stuno(1).stuname("zs").cardid(233).build();
        System.out.println(student.toString());
    }
}

2020-06-04 20:58:42.150  INFO 10884 --- [nio-8080-exec-1] c.c.b.sys.controller.StudentController   : this is log...
Student(stuno=1, stuname=zs, cardid=233)

@Cleanup

自动调用流处理的close()方法。并且自动放到try/finally中。

public void testCleanup(){
    @Cleanup BufferedReader br = null;
    try{
        FileReader fileReader = new FileReader("唐宋.txt");//定义文件
        br = new BufferedReader(fileReader);//读取文本
        System.out.println(br.readLine());//读取一行内容
    } catch (Exception e) {
        e.printStackTrace();
    }
}

---相当于---

public void testCleanup(){
    BufferedReader br = null;
    try{
        FileReader fileReader = new FileReader("唐宋.txt");//定义文件
        br = new BufferedReader(fileReader);//读取文本
        System.out.println(br.readLine());//读取一行内容
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        try{
            br.close();// 无论如何文件句柄在使用结束后得手动关闭!
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

@SneakyThrows

简化异常,自动补全try/catch。
注意:别人调用你编写的函数,并不能显式的获知需要处理哪些异常,这样容易留坑!

@SneakyThrows
public void testCleanup(){
    @Cleanup BufferedReader br = null;
    FileReader fileReader = new FileReader("唐宋.txt");//定义文件
    br = new BufferedReader(fileReader);//读取文本
    System.out.println(br.readLine());//读取一行内容
}

@Synchronized

类似于 synchronized 关键字,只能注释在静态方法和实例方法上
如果部署单机服务需要用到互斥锁,那么这个注解也可以起到作用。如果部署集群或分布式应用,就不会起到互斥作用,需要引入分布式锁的概念。

另外,@Synchronized 锁定的作用域与 synchronized 加在方法上的作用域一致,但是不推荐直接加在方法上,应在使用到互斥的方法体中进行锁定


@Getter(lazy=true)

生成第一次调用此getter时计算的值,然后将其缓存。如果计算该值占用大量 CPU 或改值占用大量内存,那么推荐使用此注解。
如果使用此注解,那么请创建一个 private final 变量,标记 @Getter(lazy=true) 注解,在这里不必考虑线程安全问题,lombok 负责锁定该资源.

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

---相当于---

public class GetterLazyExample {

    private final java.util.concurrent.atomic.AtomicReference<java.lang.Object> cached = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>();

    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;
    }
}
Last modification:June 7th, 2020 at 09:43 pm
喵ฅฅ