Lombock
第一章 介绍
- 一个优秀的Java代码库,简化了Java的编码,为Java代码的精简提供了一种方式
- 你是否发现每个JavaBean都会写getter,setter,equals,hashCode和toString的模板代码,特别的多于没技术
- lombok消除Java的冗长代码,尤其是对于简单的Java对象,只要加上注解就行
使用方式
-
添加依赖
- scope=provided,说明它只在编译阶段生效,不需要打入包中, Lombok在编译期将带Lombok注解的Java文件正确编译为完整的Class文件
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> <scope>provided</scope> </dependency>
-
添加IDE工具对Lombok的支持
- 点击File-- Settings设置界面,安装Lombok插件,然后重启idea
第二章 Setter/Getter
2.1 基本介绍
常见注解@Getter/@Setter
- 作用类上,生成所有成员变量的getter/setter方法
- 作用于成员变量上,生成该成员变量的getter/setter方法
进一步控制
- 方法控制访问级别 set和get注解加上
- @Getter(AccessLevel.PROTECTED)
- 不生成set、get方法
- @Getter(AccessLevel.NONE)
2.2 代码案例
@Setter
@Getter
public class User {
/**
* 不想生成 get方法
*/
@Getter(AccessLevel.NONE)
private int age;
/**
* 控制访问权限
*/
@Getter(AccessLevel.PROTECTED)
private int salary;
/**
* final 只会生成get
*/
private final String name="柠檬啦灬";
/**
* 下面两个静态成员变量不会生成set/get方法
*/
static Date createTime = new Date();
private static final String address = "M78";
}
2.3 字节码 mvn compile
public class User {
private int age;
private int salary;
private final String name = "柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
public User() {
}
public void setAge(int age) {
this.age = age;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getName() {
this.getClass();
return "柠檬啦灬";
}
protected int getSalary() {
return this.salary;
}
}
第三章 NonNull
3.1 基本介绍
@NonNull
- 作用于方法上或者属性,用于非空判断,如果为空则抛异常
3.2 代码案例
public void test(@NonNull String email){
this.email = email;
}
3.3 字节码
public void test(@NonNull String email) {
if (email == null) {
throw new NullPointerException("email is marked non-null but is null");
} else {
this.email = email;
}
}
第四章 构造函数注解ArgsConstructor
4.1 基本介绍
@NoArgsConstructor
- 生成无参构造器
@AllArgsConstructor
- 生成全参构造器
@RequiredArgsConstructor
- 指定参数的构造函数,有以下的特征的字段
- final类型未被初始化的属性, 标记了@NonNull的属性
- 注意:@NoArgsConstructor不能加
4.2 代码案例
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int age;
private int salary;
private final String name="柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
}
@AllArgsConstructor
@RequiredArgsConstructor
public class User {
private int age;
private int salary;
private final String name="柠檬啦灬";
@NonNull
private final String nickname;
static Date createTime = new Date();
private static final String address = "M78";
}
4.3 字节码
public class User {
private int age;
private int salary;
private final String name = "柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
public User() {
}
public User(int age, int salary) {
this.age = age;
this.salary = salary;
}
}
public class User {
private int age;
private int salary;
private final String name = "柠檬啦灬";
@NonNull
private final String nickname;
static Date createTime = new Date();
private static final String address = "M78";
public User(int age, int salary, @NonNull String nickname) {
if (nickname == null) {
throw new NullPointerException("nickname is marked non-null but is null");
} else {
this.age = age;
this.salary = salary;
this.nickname = nickname;
}
}
public User(@NonNull String nickname) {
if (nickname == null) {
throw new NullPointerException("nickname is marked non-null but is null");
} else {
this.nickname = nickname;
}
}
}
第五章 toString()注解
5.1 基本介绍
java bean对象为啥要重写toString方法?
- List或者其他集合调试不方便
- 控制台或者日志输出对象,默认打印的是内存地址
@ToString
- 作用于类,覆盖默认的toString()方法
不包括某个字段:@ToString(exclude = {"age"})
只输出某个字段:@ToString(of = {"name"})
5.2 代码案例
@ToString
public class User {
private int age;
private int salary;
private final String name="柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
}
5.3 字节码
public class User {
private int age;
private int salary;
private final String name = "柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
public User() {
}
public String toString() {
StringBuilder var10000 = (new StringBuilder()).append("User(age=").append(this.age).append(", salary=").append(this.salary).append(", name=");
this.getClass();
return var10000.append("柠檬啦灬").append(")").toString();
}
}
第六章 EqualsAndHashCode
6.1 基本介绍
@EqualsAndHashCode
- 作用于类,覆盖默认的equals和hashCode, 作用于全部属性
不包括某个属性:@EqualsAndHashCode(exclude = {"age"})
只输出某个属性:@EqualsAndHashCode(of = {"name"})
6.2 代码案例
@EqualsAndHashCode
public class User {
private int age;
private int salary;
private final String name="柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
}
6.3 字节码
public class User {
private int age;
private int salary;
private final String name = "柠檬啦灬";
static Date createTime = new Date();
private static final String address = "M78";
public User() {
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else if (this.age != other.age) {
return false;
} else if (this.salary != other.salary) {
return false;
} else {
this.getClass();
Object this$name = "柠檬啦灬";
other.getClass();
Object other$name = "柠檬啦灬";
if (this$name == null) {
if (other$name == null) {
return true;
}
} else if (this$name.equals(other$name)) {
return true;
}
return false;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
int result = result * 59 + this.age;
result = result * 59 + this.salary;
this.getClass();
Object $name = "柠檬啦灬";
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
}
第七章 Data
7.1 基本介绍
Lombok前面讲了多个注解,一个个加也麻烦吧
@Data, 定义一个干净的类,增加此注解,mvn compile查看字节码
作用于类上,是以下注解的集合
- @ToString
- @EqualsAndHashCode
- @Getter
- @Setter
- @RequiredArgsConstructor
7.2 元注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
String staticConstructor() default "";
}
第八章 建造者模式Builder
帮你生成了set、get方法,还在苦苦的一个个赋值????
构造者模式:又称之为建造者模式
- 场景:当一个bean类重载了多个构造方法时,并且参数随机使用时,考虑使用构造者模式
- 谷歌的开源的protobuf协议生产的java bean赋值就是采用建造者模式
@Builder注解
- 作用在类上
//添加
@Builder
@Data
public class StudentDO {
}
//使用
StudentDO studentDO = StudentDO.builder().age(1).email("396451989@qq").build();
System.out.println(studentDO);
第九章 Log日志输出打印@Log-@Slf4j
9.1 基本介绍
@Log / @Slf4j
- 作用于类上,生成日志变量, 用于记录日志
如果不生效,记得检查下面的配置,另外重新更新下lombok插件,重启idea
- 开始按照创建的那边,记得开启 开启annotion processing
9.2 代码案例
@Log
public class Student {
public void test(String email){
log.info("有偿解决异常加Q396451989");
this.email = email;
}
}
9.3 字节码
public class Student {
private static final Logger log = Logger.getLogger(StudentDO.class.getName());
}
第十章 Lombok插件原理-对比反射技术
光会用就行了?肯定是不行的啊,知其所以然才行的,实现这样神器的效果是咋做的
熟悉Java自定义注解的同学已经猜到是:JSR 269插件化注解处理
- JSR 269: Pluggable Annotation Processing API
- 实现在Javac编译阶段利用“Annotation Processor”对自定义的注解进行预处理后生成真正在JVM上面执行的“Class文件
- 官网
科普
- JSR是Java Specification Requests的缩写,意思是Java 规范提案。
- 是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。
- 任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
Lombok解析流程如下
Javac 解析成AST抽象语法树后, Lombok根据自己编写的注解处理器,动态地修改 AST增加新的节点(即Lombok自定义注解所需要生成的代码),最终生成JVM可执行的字节码Class文件
可以看编译后的在target目录下的class文件
能实现上述效果的还有一个反射技术,那两个对比如何?
- 使用Annotation Processing自定义注解是在编译阶段进行修改
- JDK的反射技术是在运行时动态修改
- 结论:反射更加灵活一些但是带来的性能损耗更加大
第十一章 Lombok优点和缺点
缺点:
- Lombok的使用要求一定要在IDE中安装对应的插件,如果项目组中有一个人使用了Lombok则都要用
- 代码可读性,可调试性低,比如想知道某个类中的某个属性的getter方法都被哪些类引用
- 影响升级,如果升级到某个新版本的JDK的时候,如果其中的特性在Lombok中不支持的话就会受到影响
注意常见的细节点
-
比如只使用了@Data,而不使用@EqualsAndHashCode(callSuper=true)的话,会默认是@EqualsAndHashCode(callSuper=false),这时候生成的equals()方法只会比较子类的属性,不会考虑从父类继承的属性,无论父类属性访问权限是否开放,只要知道是否需要使用父类的属性即可,也提供定制化配置,所以不用过多担心
-
优点:
- 使用注解即可帮忙自动生成代码
- 大大减少了代码量,使代码非常简洁
- 部分注解在业务项目中开发能大大提高效率
-
项目中应该用还是不用呢
- 不建议开发中间件的项目使用,中间件设计的要求是解耦少依赖
- 业务项目实体类可以用,且用的时候知道对应的常见的注解原理