每天早上八点,准时推送干货
一、介绍
Java,作为一款非常热门的编程语言,尽管它有着非常丰富的语言特性,完全面向对象编程,编程高度规范化,但是也有一个最受大家诟病的一个缺点:啰嗦,尤其是当你开发了很多年之后,你会明显的感受到,相比动态语言,java 定义变量之前,要先创建类,然后定义变量类型,每个类要写很多的get/set/toString/hashCode/equals
等等方法。
尤其是当一个实体类,高达几十个变量时,写完get、set
方法之后,一个实体类的长度快接近一千行。
为了避免写这些“罗嗦”的方法,很多程序员一直在寻觅着找一个能够使他们摆脱这种重复劳动工作的工具,例如:idea、eclipse 开发工具的快捷生成get、set
方法的工具,还有我们今天要谈论的这个Lombok
工具。
二、Lombok
Lombok 是一款非常流行的代码简洁工具,利用它的注解特性,直接就可以帮我们省去高大几百行的get、set
方法,操作非常方便。
如果是idea
开发工具,可以直接在preferences -> plugins
里面搜索lombok
,然后点击安装即可!
接着,在项目工程中导入lombok
依赖包!
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
最后,只需要在对应的实体类上加上@Data
注解,即可完成类属性get/set
的注入。
import lombok.Data;
@Data
public class User {
private String id;
private String age;
private String name;
//可以不用显式写get、set方法
}
使用@Data
注解在类上,这个实体类中的属性就不需要显式写get
、set
方法了。
对这个类进行编译之后,我们打开User.class
文件,看看编译后的文件内容长啥样?
public class User {
private String id;
private String age;
private String name;
public User() {
}
public String getId() {
return this.id;
}
public String getAge() {
return this.age;
}
public String getName() {
return this.name;
}
public void setId(String id) {
this.id = id;
}
public void setAge(String age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
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 {
label47: {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id == null) {
break label47;
}
} else if (this$id.equals(other$id)) {
break label47;
}
return false;
}
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age != null) {
return false;
}
} else if (!this$age.equals(other$age)) {
return false;
}
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(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 ($id == null ? 43 : $id.hashCode());
Object $age = this.getAge();
result = result * 59 ($age == null ? 43 : $age.hashCode());
Object $name = this.getName();
result = result * 59 ($name == null ? 43 : $name.hashCode());
return result;
}
public String toString() {
return "User(id=" this.getId() ", age=" this.getAge() ", name=" this.getName() ")";
}
}
很清晰的看到,使用@Data
注解之后,User
类新增了get
、set
、hashCode
、equals
和toString
方法。
通过上面的例子,大家可以发现,使用@Data
注解可以大大减少了代码量,使代码非常简洁,这也是很多开发者热衷于使用Lombok
的主要原因。
Lombok
的工作原理是怎么实现的呢?
由于Java
的官方版本没有提供这种快速生成方法的注解工具,类似Lombok
这样的工具,其实都是使用了从Java 6
和JSR 269
的Annotation Processing
技术中实现方法的注入。
简单的说,就是使用了 Java 非公开的 API,在 javac 编译代码时,通过强类型转换获取
JavacAnnotationProcessor
对象,再从JavacAnnotationProcessor
的方法里面拿到抽象语法树(AST)做强制修改,注入get、set
等方法。
使用Lombok
这种方案,有个最大的好处,就是可以节省大量的重复代码,让代码更佳简洁!但是也有很多弊端!
三、有哪些坏处呢?
3.1、强迫队友也安装 Lombok
当你在使用Lombok
工具插件来快速开发项目的时候,如果别的同事也要和你一起协作开发项目,那么他不得不也要安装Lombok
插件,不然项目编译会报错。
3.2、代码可调试性降低
代码可调试性会降低,为什么会这么说呢?
Lombok
虽然给我们节省了get
和set
方法的编程,但是如果我想知道类的某个属性被哪些方法操作给set
了,如果用原生的方法,可以很好的知道调用方。但是如果使用Lombok
插件来生成,这个时候你根本无从得知。甚至没办法调试!
3.3、不懂 Lombok 注解,会踩坑
我们知道,使用@Data
会重写hashCode()
和equals()
方法,如果是单个实体类,没有继承的话,你使用@Data
不会产生问题。
但是如果这个实体类又继承了父类,@Data
只会重写子类的hashCode()
和equals()
方法,不会把父类的属性加进去,这样就会导致,例如当你在使用HashMap
的时候,用当前这个实体类作为key
,可能会得到意想不到的结果。
遇到这种情况,你可以在类上加上这个注解@EqualsAndHashCode(callSuper=true)
,子类的hashCode()
和equals()
方法会加入父类的属性。
3.4、破坏封装性
封装是 java 面向对象编程中非常重要的一个特性。
例如,针对User
实体类,我新家一个tag
属性,我只想暴露它的get
方法,不想暴露set
方法给外部,没有用@Data
注解的时候,我可以很灵活的进行编程,但是使用@Data
注解之后,属性tag
被完全暴露在外界了。
public class User {
private String id;
private String age;
private String name;
private String tag = "学生";
public String getTag() {
return tag;
}
}
3.5、影响 jdk 升级
其实以上的坑点,都不算什么很大的坑点,在我看来,最大的坑点其实就是Lombok
的工作原理,使用了非官方支持的 API 接口,通过程序强制植入方式来修改类,实现get
、set
等方法的注入。
按照如今 JDK 的升级频率,每半年都会推出一个新的版本,但是Lombok
作为一个第三方工具,并且是由开源团队维护的,那么他的迭代速度是无法保证的。
假如某天JDK
把这种后门堵住了,那Lombok
基本上就不能用了,到时候又是个麻烦事情。
四、总结
Lombok 作为一款非常流行的工具插件,肯定有它自身的优势所在,到底建不建议在日常开发中使用,我个人其实是一个中立的态度,如果你们团队的人都喜欢它,那推荐你使用,在使用之前,最好培训一下,有哪些坑点,避免踩坑。
如果多数人不太喜欢用它,那就不推荐你使用,很多公司禁止你使用它的原因,其实这种插件有点类似那种流氓插件,工作原理不是官方所认可的方式来实现,假如某天新版本的 jdk 突然把这个漏洞给堵住了,那么项目想要升级 jdk,就比较困难。
因此大家在评估要不要在代码中引入Lombok
的时候,在想它的优点同时,能够考虑到它会带来的哪些问题,那么本文的目的也就达到了!
五、参考
1、https://projectlombok.org/
2、https://time.geekbang.org/column/article/164907
3、http://blog.itpub.net/69908877/viewspace-2676272/