文章目录
一、简介
在Java开发中,我们经常需要写一些Bean类,这些的结构基本相同,一堆成员变量,一个无参构造器,一堆getter和setter。虽然可以使用IDE的快捷键帮助我们生成getter和setter方法,但是当一个类的字段过多的时候,那些getter/setter、各种构造器、hashCode()还有equals()等一大堆,难道不会让代码很难看吗?
在这样的环境下lombok应运而生,lombok提供一组注解和IDE(eclipse和IDEA)的插件,帮助我们在编译期完成包括但不限于上述的代码的工具。这些注解都是编译期有效的,所有工作在编译期完成,也就是说,在编写Java Bean的时候给它加上lombok的注解,最终得到的class文件和我们直接写的其实是没有区别的。
二、安装插件
要使用lombok必先要在集成开发环境中安装插件:
- 在eclipse中安装
到https://projectlombok.org/download下载jar,到下载的目录打开命令行,敲入
java -jar lombok.jar
然后就会跳出lombok的安装程序,按照提示选择eclipse的安装目录,等待安装完即可。如下图所示:(因为我的机子既有eclipse也有myEclipse,所以这里显示了两个目录,选择自己要安装的就行了)
小技巧:在windows的资源管理器中按住shift+鼠标右键可以在当前目录打开命令行。
- 在IDEA中安装
在IDEA中安装插件都是比较容易的:File -> Setting -> Plugins,然后输入lombok搜索插件,然后点击右边的install,这里我已经安装好了,所以就显示了uninstall
三、如何使用
安装了插件之后,自己的项目中添加lombok的maven依赖,或者加入lombok的jar包到项目中(但现在谁还会直接使用jar而不用maven呢?)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
现在可以在项目中享受lombok带来的便利了。先看一个例子:
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private Integer sex;
private String name;
}
public static void main(String[] args) {
Student student = new Student();
student.setName("jim");
System.out.println(student);
}
控制台打印结果为:
Student(id=null, sex=null, name=jim)
神奇吧~
四,相关API介绍
lombok能够使用的注解都在lombok包下面,以下挑一些常用的讲解,也可以直接看源码,看注释就知道这个注解有什么作用。
在lombok.experimental包下面也有提供更多的注解,这些都属于实验阶段,也可以使用,但是不保证今后会不支持。
@Getter、@Setter
这两个注解可以使用在字段或者类上面。当使用在字段上面,为当前字段生成getter/setter;当使用在类上面的时候为该类所有字段生成getter/setter。如:
@Getter
@Setter
public class Student {
private Integer id;
private Integer sex;
private String name;
}
生成的class文件:
public class Student {
private Integer id;
private Integer sex;
private String name;
public Student() {
}
public Integer getId() {
return this.id;
}
public Integer getSex() {
return this.sex;
}
public String getName() {
return this.name;
}
public void setId(Integer id) {
this.id = id;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public void setName(String name) {
this.name = name;
}
}
@NoArgsConstructor
使用在类上面,为该类生成一个无参构造器。如:
@NoArgsConstructor
public class Student {
private Integer id;
private Integer sex;
private String name;
}
则生成class为:
public class Student {
private Integer id;
private Integer sex;
private String name;
public Student() {
}
}
@AllArgsConstructor
为该类生成全部参数的构造器。如:
@AllArgsConstructor
public class Student {
private Integer id;
private Integer sex;
private String name;
}
则生成:
public class Student {
private Integer id;
private Integer sex;
private String name;
public Student(Integer id, Integer sex, String name) {
this.id = id;
this.sex = sex;
this.name = name;
}
}
@ToString
@ToString也是使用在类上面,为该类的所有字段生成toString方法,跟直接在Eclipse中生成的是一样的,如:
@ToString
public class Student {
private Integer id;
private Integer sex;
private String name;
}
生成:
public class Student {
private Integer id;
private Integer sex;
private String name;
public Student() {
}
public String toString() {
return "Student(id=" + this.id + ", sex=" + this.sex + ", name=" + this.name + ")";
}
}
@EqualsAndHashCode
注解在类上面,为该类生成equals和hashCode方法,如:
@EqualsAndHashCode
public class Student {
private Integer id;
private Integer sex;
private String name;
}
则该类生成:
public class Student {
private Integer id;
private Integer sex;
private String name;
public Student() {
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Student)) {
return false;
} else {
Student other = (Student)o;
if (!other.canEqual(this)) {
return false;
} else {
label47: {
Object this$id = this.id;
Object other$id = other.id;
if (this$id == null) {
if (other$id == null) {
break label47;
}
} else if (this$id.equals(other$id)) {
break label47;
}
return false;
}
Object this$sex = this.sex;
Object other$sex = other.sex;
if (this$sex == null) {
if (other$sex != null) {
return false;
}
} else if (!this$sex.equals(other$sex)) {
return false;
}
Object this$name = this.name;
Object other$name = other.name;
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 Student;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.id;
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $sex = this.sex;
result = result * 59 + ($sex == null ? 43 : $sex.hashCode());
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
}
@Data
@Data是@Getter、@Setter、@ToString和@EqualsAndHashCode等的大合集,直接使用一个@Data注解,等同于使用后者全部,如下例子:
public class Student {
private Integer id;
private Integer sex;
private String name;
public Student() {
}
public Integer getId() {
return this.id;
}
public Integer getSex() {
return this.sex;
}
public String getName() {
return this.name;
}
public void setId(Integer id) {
this.id = id;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Student)) {
return false;
} else {
Student other = (Student)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$sex = this.getSex();
Object other$sex = other.getSex();
if (this$sex == null) {
if (other$sex != null) {
return false;
}
} else if (!this$sex.equals(other$sex)) {
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 Student;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $sex = this.getSex();
result = result * 59 + ($sex == null ? 43 : $sex.hashCode());
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
public String toString() {
return "Student(id=" + this.getId() + ", sex=" + this.getSex() + ", name=" + this.getName() + ")";
}
}
@Builder
@Builder是构建者模式,使用在类上,可以为该类生成一个内部Builder类,可以使用该Builder类来生成一个实际的类,如下代码所示。
这里注意到,使用@Builder时候会生成一个全部参数的构造器,默认是default权限的。请注意,@Builder是不能和@NoArgsConstructor同时使用的。另外,如果@Builder和@AllArgsConstructor同时使用,生成的全参构造器的权限是public的,这是由@AllArgsConstructor和access属性来控制的,具体可以点进去看看这个属性,可以通过这个属性改变生成的构造器的权限修饰符。
@Builder
public class Student {
private Integer id;
private Integer sex;
private String name;
}
public class Student {
private Integer id;
private Integer sex;
private String name;
@ConstructorProperties({"id", "sex", "name"})
Student(Integer id, Integer sex, String name) {
this.id = id;
this.sex = sex;
this.name = name;
}
public static Student.StudentBuilder builder() {
return new Student.StudentBuilder();
}
public static class StudentBuilder {
private Integer id;
private Integer sex;
private String name;
StudentBuilder() {
}
public Student.StudentBuilder id(Integer id) {
this.id = id;
return this;
}
public Student.StudentBuilder sex(Integer sex) {
this.sex = sex;
return this;
}
public Student.StudentBuilder name(String name) {
this.name = name;
return this;
}
public Student build() {
return new Student(this.id, this.sex, this.name);
}
public String toString() {
return "Student.StudentBuilder(id=" + this.id + ", sex=" + this.sex + ", name=" + this.name + ")";
}
}
}
lombok.experimental包
@UtilityClass
该注解使用在类上,使用这个注解后,这个类会
1,最终类,final修饰
2,不能定义构造器,会提供一个private的构造器
3,该类所有方法、字段和内部类都会加上static修饰
其实就是一个工具类常有的做法。如:
@UtilityClass
public class DBUtils {
private Connection connection;
public Connection getConnection() {
return connection;
}
}
则生成:
public final class DBUtils {
private static Connection connection;
public static Connection getConnection() {
return connection;
}
private DBUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}
@FieldDefaults
@FieldDefaults使用在类上面,指定该类的字段的权限修饰符,使用这个注解会为该类所有没指明权限修饰符的字段生成修饰符,如下代码。
这里id字段我指明为public最终生成的class中也是public,sex和name字段没有指明修饰符,则按照@FieldDefaults中的level属性,设置修饰符为private。
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Student {
public Integer id;
Integer sex;
String name;
}
public class Student {
public Integer id;
private Integer sex;
private String name;
public Student() {
}
}
日志相关的注解
@CommonsLog、@Log 、@JBossLog、@Log4j、@Log4j2、@Slf4j、@XSl4j
这些都是使用在类上面,为该类生成一个private staitc fianl的名字为log的日志成员变量,唯一的区别就是使用的日志类不同。需要注意的是,在使用这些注解的项目中要添加相应的maven依赖。如:
@Log4j
public class LogExample {
public void userLog() {
log.info("使用生成的log对象");
}
}
编译后:
import org.apache.log4j.Logger;
public class LogExample {
private static final Logger log = Logger.getLogger(LogExample.class);
public LogExample() {
}
public void userLog() {
log.info("使用生成的log对象");
}
}
其他的类似,都会生成相应的log对象
- @CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
- @Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
- @JBossLog
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
- @Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
- @Log4j2
private static final org.apache.logging.log4j.Logger log = rg.apache.logging.log4j.LogManager.getLogger(LogExample.class);
- @Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
- @XSl4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
五、总结
是不是感觉上面都是贴代码,一大堆繁杂的代码??那就对了,对比一下使用lombok和不使用lombok,代码量差距不要太大。实际开发中,有时候一个bean光是字段就有几十个,要是还写一大堆的Getter和Setter,构造器什么的,这代码,简直不敢看。而使用了lombok之后,在程序编译期就会为我们生成一样的代码,虽然我们在源文件中看到的没有那些代码,但经过编译后就有了,效果是一样的。