1.什么是Lombok?
Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的Java模型对象(POJO)。
在开发环境中使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。
2.常用注解
@NoArgsConstructor/@AllArgsConstructor
@NoArgsConstructor/@AllArgsConstructor就是为该类产生无参的构造方法和包含所有参数的构造方法
/**
* @ClassName User
* @Description TODO
* @Author liuhaihua
* @Date 2024/9/17 17:20
* @Version 1.0
*/
@AllArgsConstructor
public class User {
private String name;
private int age;
}
生成的代码如下
package com.et.lombok.model;
public class User {
private String name;
private int age;
public User(final String name, final int age) {
this.name = name;
this.age = age;
}
}
@RequiredArgsConstructor
@RequiredArgsConstructor注解则会将类中所有带有
@NonNull注解 / org.jetbrains.annotations.NotNull注解
的或者带有
final修饰的成员变量
生成对应的构造方法
package com.et.lombok.model;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class Demo {
@NonNull
private String name;
@NonNull
private int age;
}
生成的代码如下
package com.et.lombok.model;
import lombok.NonNull;
public class Demo {
@NonNull
private String name;
@NonNull
private int age;
public Demo(@NonNull final String name, @NonNull final int age) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
this.name = name;
this.age = age;
}
}
}
@Getter/@Setter
这一对注解从名字上就很好理解,用在成员变量上面或者类上面,相当于为成员变量生成对应的get和set方法,
同时还可以为生成的方法指定访问修饰符,当然,默认为public
package com.et.lombok.model;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@Getter
@Setter
public class Demo1 {
private String name;
private int age;
}
生成的代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
public class Demo1 {
private String name;
private int age;
public Demo1() {
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(final String name) {
this.name = name;
}
public void setAge(final int age) {
this.age = age;
}
}
这两个注解直接用在类上,可以为此类里的所有非静态成员变量生成对应的get和set方法。如果是final变量,那就只会有get方法
@ToString/@EqualsAndHashCode
这两个注解也比较好理解,就是生成toString,equals和hashcode方法,同时后者还会生成一个canEqual方法,用于判断某个对象是否是当前类的实例。
生成方法时只会使用类中的非静态成员变量。
package com.et.lombok.model;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString(exclude="id")
@EqualsAndHashCode
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private String[] tags;
private int id;
}
生成的类如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
import java.util.Arrays;
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private String[] tags;
private int id;
public ToStringExample() {
}
public String toString() {
return "ToStringExample(name=" + this.name + ", tags=" + Arrays.deepToString(this.tags) + ")";
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof ToStringExample)) {
return false;
} else {
ToStringExample other = (ToStringExample)o;
if (!other.canEqual(this)) {
return false;
} else {
label31: {
Object this$name = this.name;
Object other$name = other.name;
if (this$name == null) {
if (other$name == null) {
break label31;
}
} else if (this$name.equals(other$name)) {
break label31;
}
return false;
}
if (!Arrays.deepEquals(this.tags, other.tags)) {
return false;
} else {
return this.id == other.id;
}
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof ToStringExample;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.name;
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + Arrays.deepHashCode(this.tags);
result = result * 59 + this.id;
return result;
}
}
@Data
@Data
相当于注解集合。效果等同于 @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor 效果同和这5个注解的效果
需要注意的是,这里不包括@NoArgsConstructor和@AllArgsConstructor
所以, 一般使用@Data时,要配合这两个注解一起使用
package com.et.lombok.model;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
public class Demo3 {
private String name;
private int age;
}
生成的代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
public class Demo3 {
private String name;
private int age;
public Demo3() {
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(final String name) {
this.name = name;
}
public void setAge(final int age) {
this.age = age;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Demo3)) {
return false;
} else {
Demo3 other = (Demo3)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
return this.getAge() == other.getAge();
}
} else if (this$name.equals(other$name)) {
return this.getAge() == other.getAge();
}
return false;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof Demo3;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + this.getAge();
return result;
}
public String toString() {
return "Demo3(name=" + this.getName() + ", age=" + this.getAge() + ")";
}
}
@Builder
@Builder提供了一种比较推崇的构建值对象的方式; 非常推荐的一种构建值对象的方式。
缺点就是父类的属性不能产于builder
标注@Builder的类, 会在类内部生成一个内部类,用于生成值对象
package com.et.lombok.model;
import lombok.Builder;
@Builder
public class Demo4 {
private String name;
private int age;
}
生成的代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
public class Demo4 {
private String name;
private int age;
Demo4(final String name, final int age) {
this.name = name;
this.age = age;
}
public static Demo4.Demo4Builder builder() {
return new Demo4.Demo4Builder();
}
public static class Demo4Builder {
private String name;
private int age;
Demo4Builder() {
}
public Demo4.Demo4Builder name(final String name) {
this.name = name;
return this;
}
public Demo4.Demo4Builder age(final int age) {
this.age = age;
return this;
}
public Demo4 build() {
return new Demo4(this.name, this.age);
}
public String toString() {
return "Demo4.Demo4Builder(name=" + this.name + ", age=" + this.age + ")";
}
}
}
用法
package com.et.lombok.model;
import com.et.lombok.model.Demo4;
public class Main {
public static void main(String[] args) {
Demo4 demo = Demo4.builder().name("zss").age(20).build();
System.out.println(demo);
}
}
@Accessors
@Accessors 一个为getter和setter方法设计的更流畅的注解
这个注解要搭配@Getter与@Setter使用,用来修改默认的setter与getter方法的形式。
@Accessors属性详解
- fluent 属性 : 链式的形式 这个特别好用,方法连缀越来越方便了
- chain 属性 : 流式的形式(若无显示指定chain的值,也会把chain设置为true)
- prefix 属性 : 生成指定前缀的属性的getter与setter方法,并且生成的getter与setter方法时会去除前缀
package com.et.lombok.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
@Getter
@Setter
@ToString
@Accessors(fluent = true)
public class Demo5 {
private String name;
private int age;
}
代码如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
public class Demo5 {
private String name;
private int age;
public Demo5() {
}
public String name() {
return this.name;
}
public int age() {
return this.age;
}
public Demo5 name(final String name) {
this.name = name;
return this;
}
public Demo5 age(final int age) {
this.age = age;
return this;
}
public String toString() {
return "Demo5(name=" + this.name() + ", age=" + this.age() + ")";
}
}
@SneakyThrows
这个注解用在方法上,可以将方法中的代码用try-catch语句包裹起来,捕获异常并在catch中用Lombok.sneakyThrow(e)把异常抛出,可以使用@SneakyThrows(Exception.class)的形式指定抛出哪种异常
package com.et.lombok.model;
import lombok.SneakyThrows;
import java.io.UnsupportedEncodingException;
public class Main1 {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF8");
}
}
生成的代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
import java.io.UnsupportedEncodingException;
public class Main1 {
public Main1() {
}
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF8");
} catch (UnsupportedEncodingException var3) {
throw var3;
}
}
}
@Value
@Value注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法。
@Cleanup
这个注解用在局部变量
上,可以保证此变量代表的资源会被自动关闭,默认是调用资源的close()方法。
如果该资源有其它关闭方法,可使用
@Cleanup(“methodName”)
来指定要调用的方法,就用输入输出流来举个例子吧:
package com.et.lombok.model;
import lombok.Cleanup;
import lombok.SneakyThrows;
import java.io.*;
public class Main2 {
@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);
}
}
}
生成的代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.et.lombok.model;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Collections;
public class Main2 {
public Main2() {
}
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
这个注解可以用在成员方法或者构造方法的参数上,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常。
@Synchronized
这个注解用在类方法或者实例方法上,效果和synchronized关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象
而@Synchronized得锁对象分别是私有静态final对象lock和私有final对象lock,当然,也可以自己指定锁对象
注意: 属性value指定锁对象,当锁对象不存在时,则编译不通过,默认为 “”
@Slf4j注解
Slf4j日志门面(Simple Logging Facade For Java) , Slf4j主要是为了给Java日志访问提供一套标准、规范的API框架,
其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等