摘要:在项目开发过程中,实体类需要通过IDEA自动生成get和set方法,非常烦琐,而且这个工作没有什么技术含量。使用Lombok可以代替这些方法的生成,只需要一个简单的注解就能完成之前烦琐的创建过程,从而提高开发者的开发效率。下面介绍Lombok的原理和使用。
在项目开发过程中,实体类需要通过IDEA自动生成get和set方法,非常烦琐,而且这个工作没有什么技术含量。使用Lombok可以代替这些方法的生成,只需要一个简单的注解就能完成之前烦琐的创建过程,从而提高开发者的开发效率。下面介绍Lombok的原理和使用。
Lombok是一个java插件,它通过注解来简化一些臃肿的Java代码,尤其适用于Java实体类对象。例如,新建一个实体类,然后添加几个属性,通常使用IDEA自动生成属性的get和set方法与构造函数,Lombok不再手动生成这些方法,它会在源码编译时自动生成,项目开发时,只需要添加相应的注解即可。
Lombok插件是在编译期起作用的,它在编译时生效的具体流程如下:
(1)Java编译器对源代码进行分析,生成一棵抽象语法树(AST)。
(2)运行过程中调用实现了JSR 269 API的Lombok程序。
(3)Lombok对抽象语法树进行处理,找到标记有@Data注解的类所对应的语法树,然后修改该语法树,增加get和set方法定义的相应树节点。
(4)编译器使用修改后的抽象语法树生成字节码文件,即在编译后的class文件中添加get和set方法。
(5)查看反编译后的class文件,即可看到生成后的方法代码。
要在项目开发中使用Lombok,需要先为IDE安装Lombok插件,下面分别介绍Eclipse和IDEA的Lombok插件的安装步骤。
1. Eclipse插件的安装方法
(1)下载Lombok插件的jar包,本次使用的插件版本为1.12.6。
(2)把下载好的Lombok的jar包放到eclipse的安装目录下,本机为D:\Program Files (x86)\eclipse,请更换为自己的计算机目录。
(3)执行以下命令,为Eclipse安装Lombok插件,显示效果如图2.16所示。
java -jar D:\Program Files (x86)\eclipse\lombok-1.12.6.jar
图2.16 Lombok插件的安装
只需要选中需要安装的Eclipse,选择Install/Update命令就可以进行安装。安装完成后查看Eclipse的配置文件eclipse.ini,发现其增加了两行配置,如图2.17所示。
图2.17 Eclipse中Lombok的配置
至此Lombok插件安装成功,可以在Eclipse中使用Lombok的注解进行项目开发了。
2. IDEA插件的安装方法
(1)首先打开IDEA的设置,单击Plugins选项,会出现如图2.18所示的界面。
图2.18 IDEA的插件安装页面
(2)在搜索框中输入“lombok”进行搜索,结果如图2.19所示。单击Install按钮就可以安装(因为本机已经安装了Lombok,所以这里显示Installed),安装完成后,会提示重启IDEA,重启完成后就可以使用Lombok的注解进行开发了。
图2.19 Lombok插件安装
要使用Lombok,需要添加Lombok的Maven依赖,其代码如下
org.projectlombok
lombok
1.16.12
在项目开发过程中,Java类只有固定的几个方法可以使用注解自动生成,包括get/set方法、构造方法和ToString方法等。常用的Lombok注解参见表2.5。
下面演示@Builder注解的使用过程。
(1)新建com.onyx.springbootdemo.vo包,在其中添加一个测试类Test,代码如下:
import lombok.Builder;
public class Test {
public static void main(String args) {
//手动创建set方法
User1 user1 = new User1; user1.setId(1);
user1.setName("cc");
//Builder注解后的链式写法
User2 user2 = User2.builder.id(1).name("cc").build;
}
private static class User1{
private int id;
private String name;
public int getId {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//@Builder注解
@Builder
private static class User2{
private int id;
private String name;
}
}
查看Test类编译后的class文件反编译后的文件,编译器已经把Lombok的注解去掉,并且添加了相应的注解方法。以下为反编译文件,此文件在target\classes\(包名)目录下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//import java.beans.ConstructorProperties;
public class Test {
public Test {
}
public static void main(String args) {
Test.User1 user1 = new Test.User1;
user1.setId(1);
user1.setName("cc");
Test.User2 user2 =
Test.User2.builder.id(1).name("cc").build;
}
private static class User2 {
private int id;
private String name;
@ConstructorProperties({"id", "name"})
User2(final int id, final String name) {
this.id = id;
this.name = name;
}
public static Test.User2.User2Builder builder {
return new Test.User2.User2Builder;
}
public static class User2Builder {
private int id;
private String name;
User2Builder {
}
public Test.User2.User2Builder id(final int id) {
this.id = id;
return this;
}
public Test.User2.User2Builder name(final String name) {
this.name = name;
return this;
}
public Test.User2 build { return new Test.User2(this.id, this.name);
}
public String toString {
return "Test.User2.User2Builder(id=" + this.id + ",
name=" + this.name + ")";
}
}
}
private static class User1 {
private int id;
private String name;
private User1 {
}
public int getId {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
}
如果类上标记@SLF4J,相当于以下代码,这样就能使用日志组件:
/** logger日志 */
private static final Logger log =
LoggerFactory.getLogger(Product.class);
(2)新建Product类,源码如下:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Data
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private int id;
private String name;
}
反编译后的文件代码如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log =
LoggerFactory.getLogger(Product.class);
private int id;
private String name;
public int getId {
return this.id;
}
public String getName {
return this.name;
}
public void setId(final int id) { this.id = id;
}
public void setName(final String name) {
this.name = name;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Product)) {
return false;
} else {
Product other = (Product)o;
if (!other.canEqual(this)) {
return false;
} else if (this.getId != other.getId) {
return false;
} else {
Object this$name = this.getName;
Object other$name = other.getName;
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof Product;
}
public int hashCode {
int PRIME = true;
int result = 1;
int result = result * 59 + this.getId;
Object $name = this.getName; result = result * 59 + ($name == null ? 43 : $name.hashCode);
return result;
}
public String toString {
int var10000 = this.getId;
return "Product(id=" + var10000 + ", name=" + this.getName +
")";
}
//空参构造
public Product {
}
//全参构造器
public Product(final int id, final String name) {
this.id = id;
this.name = name;
}
}
根据笔者的开发经验,在项目中使用Lombok有以下几个注意点:
@Data注解实现了@EqualsAndHashCode的功能,如果一个类继承的父类使用了@EqualsAndHashCode(callSuper = true)注解,则当前类由Lombok生成的equals方法只有在两个对象相同时才会返回true,否则为false,无论它们的属性是否相同。这个特性是不符合预期的,对于这种情况可以重写equals,而Lombok不会影响开发者已经重写的方法,如toString方法。
解决方法:
(1)用了@Data就不要有继承关系,类似于Kotlin的做法。
(2)自己重写equals,Lombok不会影响开发者已经重写的方法,如toString方法。
(3)显式地使用@EqualsAndHashCode(callSuper=true),Lombok会以显式指定的equals方法和hashcode方法为准。
来源:程序员高级码农II一点号