快速上手使用Lombok简化开发!
一、什么是Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
Project Lombok是一个java库,它会自动插入到你的编辑器和构建工具中,为你的java增添色彩。
再也不用编写另一个 getter 或 equals 方法,只需一个注释,您的类就会有一个功能齐全的构建器,自动执行日志记录变量等等。 ---- 摘自官网
简而言之:Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。
二、快速使用Lombok
1.引入坐标
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
2.安装插件
在IDEA开发工具中使用Lombok时,需要安装Lombok插件来配合,好像现在新版的IDEA都已经内置了该插件,如果没有可以按照下面的操作进行按照即可!
打开IDEA的设置,点击Plugins,点击Browse repositories,在弹出的窗口中搜索lombok,然后安装即可。
3.使用示例
3.1不使用Lombok开发实体类
package cn.imyjs.mp.pojo;
/**
* @Classname Student
* @Description TODO
* @Date 2022/4/24 15:04
* @Created by YJS
* @WebSite www.imyjs.cn
*/
public class Student {
private Long id;
private String name;
private Integer age;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
此时需要我们去手写实体类的Geter、Seter、toString、equals等方法,以及无参构造和全参构造器等,即使有许多一键自动生成的插件来简化这部分代码的手动书写,但是如果项目过于复杂的情况下,无疑也是一件头疼的事情,而且如果某实体类字段很多,还会导致代码冗长,不利于阅读和维护。那么此时使用Lombok就可以解决这些烦恼,往下看!
3.2使用Lombok开发实体类
package cn.imyjs.mp.pojo;
import lombok.Data;
/**
* @Classname Student
* @Description TODO
* @Date 2022/4/24 15:04
* @Created by YJS
* @WebSite www.imyjs.cn
*/
@Data
public class Student {
private Long id;
private String name;
private Integer age;
private String address;
}
没错,此时这种写法与上边的写法效果相同,并且还提供hashcode等方法。只因为在这个类上加了一个
@Data
注解。
三、常用注解
1.变量相关
1.@NonNull
作用
这个注解会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常。
使用范围
方法参数上
Lombok将在方法/构造函数体的开头插入一个空检查,并将参数的名称作为消息引发一个NullPointerException
字段上
任何为该字段赋值的生成方法也将生成这些空检查
示例
//成员方法参数加上@NonNull注解
public String getName(@NonNull Person p){
return p.getName();
}
等价于:
public String getName( Person p){
if(p==null){
throw new NullPointerException("person");
}
return p.getName();
}
2.@Cleanup
作用
可以保证此变量代表的资源会被自动关闭,默认是调用资源的close()方法,如果该资源有其它关闭方法,可使用@Cleanup(“methodName”)来指定要调用的方法。
使用范围
这个注解用在变量
前面。
示例
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream("./a.txt");
@Cleanup OutputStream out = new FileOutputStream("./b.txt");
byte[] b = new byte[1024];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
等价于:
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream("./a.txt");
try {
OutputStream out = new FileOutputStream("./b.txt");
try {
byte[] b = new byte[1024];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}
2.实体类相关
1.@Getter & @Setter
作用
代替实体类中的geter和seter方法。
使用范围
- 用在
成员变量
前面,相当于为成员变量生成对应的get和set方法,同时还可以为生成的方法指定访问修饰符
,默认为public。 - 直接用在
类
上,可以为此类里的所有非静态成员变量
生成对应的get和set方法。
示例
public class Student {
@Getter(AccessLevel.PRIVATE)
@Setter
private Long id;
@Getter(AccessLevel.PUBLIC)
private String name;
private Integer age;
@Getter(AccessLevel.PRIVATE)
@Setter(AccessLevel.PRIVATE)
private String address;
}
方法命名
- Getter
默认情况下方法名为:get+字段名以驼峰连接。
如果是boolean类型则:is+字段名以驼峰连接。(Boolean类型是get开头)不建议使用is开头的字段命名,会产生混淆
- Setter
setter不受boolean影响:set+字段名以驼峰连接。
特殊事项
- @Getter可用于枚举而@Setter不能
- 来自流行库的注释检查,例如javax.annotation.Nonnull,如果存在于字段上,导致生成的setter中会进行显式的空检查。
- 当与@Accessors注解一起使用会产生影响
2.@Accessors
作用
修改getter和setter方法的内容。
使用范围
类或字段上
属性功能
fluent
如果为true,那么getter 和setter 生成的方法名没有前缀。此外,除非指定,否则chain将为true。
chain
如果为true,则生成的setter返回this而不是void。即可以使用链式编程。默认值:false
prefix
如果存在,则字段必须以任何这些前缀为前缀。每个字段名称依次与列表中的每个前缀进行比较,如果找到匹配项,则会剥离前缀以创建字段的基本名称。在列表中包含一个空字符串是合法的它将始终匹配。
对于字母的字符,前缀后面的字符不能是小写字母,即以p为前缀也不会匹配pepper,但是pEpper会被匹配上(并且意味着该字段的基本名称epper)。
如果提供了前缀列表并且字段不以其中一个字段开头,则lombok将完全跳过该字段,并将生成警告
示例
@Accessors(chain = true) // 开启链式编程
@Data
public class Student {
private Long id;
private String name;
private Integer age;
private String address;
}
public static void main(String[] args) {
Student student = new Student();
student.setId(1001L).setAge(18).setName("小明").setAddress("北京");
System.out.println(student);
// Student(id=1001, name=小明, age=18, address=北京)
}
3.@NoArgsConstructor/@RequiredArgsConstructor /@AllArgsConstructor
作用
@NoArgsConstructor
:生成无参构造器@AllArgsConstructor
:生成全参构造器@RequiredArgsConstructor
:使用类中所有带有@NonNull注解的或者带有final修饰的成员变量生成对应的构造方法
可以用做注入属性,在Spring中,在Controller层的类上使用@RequiredArgsConstructor标注,然后在类中创建对应的成员属性,就会自动在Controller类中,生成一个构造器,从而使属性注入。
使用范围
类上
注意
- 成员变量都是非静态的
- 如果类中含有final修饰的成员变量,是无法使用@NoArgsConstructor注解的
- 三个注解都可以指定生成的构造方法的访问权限,同时,第二个注解还可以用@RequiredArgsConstructor(staticName=”methodName”)的形式生成一个指定名称的静态方法,返回一个调用相应的构造方法产生的对象。
示例
@RequiredArgsConstructor(staticName = "testMethod")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor
public class Shape {
private int x;
@NonNull
private double y;
@NonNull
private String name;
}
等价于:
public class Shape {
private int x;
private double y;
private String name;
// @NoArgsConstructor
public Shape(){
}
// @AllArgsConstructor(access = AccessLevel.PROTECTED)
protected Shape(int x,double y,String name){
this.x = x;
this.y = y;
this.name = name;
}
// @RequiredArgsConstructor(staticName = "testMethod")
public Shape(double y,String name){
this.y = y;
this.name = name;
}
// @RequiredArgsConstructor(staticName = "testMethod")
public static Shape testMethod(double y,String name){
return new Shape(y,name);
}
}
4.@Data
作用
@Data 是 @Getter、 @Setter、 @ToString、 @EqualsAndHashCode 和 @RequiredArgsConstructor 的快捷方式。
使用范围
类上
属性配置
- staticConstructor 静态方法名
@Data(staticConstructor=“of”)
通过新的方式来创建实例:Foo.of(5)
示例
@Data(staticConstructor = "of")
public class Student {
private Long id;
private String name;
private Integer age;
private String address;
}
public static void main(String[] args) {
Student student = Student.of();
student.setName("测试staticConstructor");
System.out.println(student);
// Student(id=null, name=测试staticConstructor, age=null, address=null)
}
5.@Value
作用
@Value注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法。
使用范围
类或字段上
特点
@Value是不可变的@Data
@ToString,@EqualsAndHashCode,@AllArgsConstructor,@FieldDefaults,@Getter。
所有字段由private和final修饰,不会产生setter方法。类本身也是由final修饰
。
6.@ToString
作用
生成toString()方法
使用范围
类上
属性功能
默认情况下,Lombok 生成包含所有成员变量的 toString 方法。可以通过 exclude 属性 @ToString(exclude={"someField","someOtherField"})
覆盖行为将某些成员变量排除。或者用@ToString(of={“param1”,“param2”})
来指定使用param1和param2两个成员变量。
示例
@Setter
@ToString(exclude = {"id"})
public class Student {
private Long id;
private String name;
private Integer age;
private String address;
}
public static void main(String[] args) {
Student student = new Student();
student.setId(1001L);
student.setName("xm");
student.setAge(19);
student.setAddress("河南");
System.out.println(student);
// Student(name=xm, age=19, address=河南)
}
7.@EqualsAndHashCode
作用
自动重写toString\equals\hashCode方法,还会生成一个canEqual方法,用于判断某个对象是否是当前类的实例,生成方法时只会使用类中的非静态和非transient成员变量。
使用范围
类上
功能属性
可以通过 exclude 属性 @EqualsAndHashCode(exclude={"someField","someOtherField"})
覆盖行为将某些成员变量排除。或者用@EqualsAndHashCode(of={“param1”,“param2”})
来指定使用param1和param2两个成员变量。
示例
@Setter
@EqualsAndHashCode(of = {"name","age"})
public class Student {
private Long id;
private String name;
private Integer age;
private String address;
}
3.日志相关
1.@Slf4j
作用
为类提供一个 属性名为log 的 log4j 日志对象。
使用范围
类上
示例
@Slf4j
public class LombokTest {
public static void main(String[] args) {
log.info("我是测试{}的", "@Slf4j");
// 16:24:18.754 [main] INFO cn.imyjs.test.LombokTest - 我是测试@Slf4j的
}
}
2.@Log4j
作用
为类提供一个 属性名为log 的 log4j 日志对象。
使用范围
类上
注意
- @Log4j是具体的日志实现。而@Slf4j是一个抽象层,它允许程序使用任意一个日志类库,使程序更加独立。
- @Slf4j可以使用占位符"{}",可减少代码中字符串连接次数
4.其他注解
1.@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 {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
try{
return new String(bytes, "UTF-8");
}catch(UnsupportedEncodingException uee){
throw Lombok.sneakyThrow(uee);
}
}
@SneakyThrows
public void run() {
try{
throw new Throwable();
}catch(Throwable t){
throw Lombok.sneakyThrow(t);
}
}
}
2.@Synchronized
作用
效果和synchronized关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象,而@Synchronized得锁对象分别是私有静态final对象LOCK和私有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");
}
}
}
3.@Builder
作用
生成构建者(Builder)模式。
四、Lombok的优缺点
1.优点
- 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率。
- 让代码变得简洁,不用过多的去关注相应的方法。
- 属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等
2.缺点
- 不支持多种参数构造器的重载