# Java 开发中使用 Lombok 简化代码
# 简介
lombok (opens new window) 是什么呢?如果你不了解也没关系,接下来我会一步步带领大伙入坑的。
通俗一点讲,这就是个生成代码的框架(或者说工具、插件)。Ta 与那个同名的小岛一样美丽、优雅。
lombok 的魅力就在于可以很方便地减少 Java 应用程序中样板文件的代码量, 不需要编写那些冗余的 Java 代码,比如 Getter、Setter、构造器等。
TIP
使 Lombok
如此贴心的不只是语法,它是一种独特的代码生成方法,能够开启所有 Java 开发可能性。
我用 lombok 已经有三个年头了,最开始知道这个东东,还是一次在网上瞎逛的时候偶然发现了一个号称
JavaWeb 开发的颠覆者
的框架:Spring Boot (opens new window)。这个框架本身与 lombok 并没有直接关系,我也是在创建 boot 项目的时候看到 lombok(IDEA 或者 STS 可以看到),出于好奇就去官网瞅了瞅,看到介绍之后,我就果断入坑了,从此欲罢不能,一发不可收拾,你不信?可能是你病得太轻(代码洁癖,我已经晚期了)。
# 快速开始
项目中加入 lombok 的依赖包,同时 IDE 安装了 lombok 插件就可以使用了。
# 下载 & 安装
上边说了这么多 lombok 的好处,也说 Ta 挺坑的,原因就是 Eclipse/MyEclipse 使用不很方便,要手动安装插件,其实是 Eclipse 的坑。官方提供的 jar 其实同时也是插件,有一键安装的方法,不过不是每次都成功,很多时候还需要手动配置,久而久之,就直接手动安装了,也没几步操作。具体安装过程之前我写过一篇文章专门说这个,就不在这废话了,不知道的移步我以前写的文章。今天主要说说快速上手。
# 项目加入 lombok
准备工作相对简单一些,下载官方 jar 包 (opens new window),引入到项目中即可,也可以使用 Maven
或 Gradle
等包管理器直接引入。
# Maven
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
# Gradle
provided group: 'org.projectlombok', name: 'lombok', version: '1.16.16'
# 常用注解
TIP
以下示例均采用 Java6 编译,由于编译器版本等因素,最终输出的 class 文件内容可能会有部分差异。
我们先从最常用的开始:
# @Data
这个注解是最常用的,是一个类级别注解,同时也是一个 复合型注解
,所谓复合型注解,就是多个注解的集合体。
这个注解包含了 @Getter
、@Setter
、@ToString
、@EqualsAndHashCode
、@RequiredArgsConstructor
,每个注解的作用会在稍后一一介绍。
此注解有一个参数 staticConstructor
用来生成静态构造器,对应值为 构造器名。
使用注解的效果直接上代码:
- 源文件
import lombok.Data;
@Data(staticConstructor="of")
public class DataExample {
private final String name;
private int age;
private double score;
private String[] tags;
}
- 字节码文件
import java.beans.ConstructorProperties;
import java.util.Arrays;
public class DataExample {
private final String name;
private int age;
private double score;
private String[] tags;
@ConstructorProperties({"name"})
private DataExample(String name) {this.name = name;}
public static DataExample of(String name) {return new DataExample(name);}
public String getName() {return this.name;}
public int getAge() {return this.age;}
public void setAge(int age) {this.age = age;}
public double getScore() {return this.score;}
public void setScore(double score) {this.score = score;}
public String[] getTags() {return this.tags;}
public void setTags(String[] tags) {this.tags = tags;}
protected boolean canEqual(Object other) {return other instanceof DataExample;}
public boolean equals(Object o) {if(o == this) {return true;} else if(!(o instanceof DataExample)) {return false;} else {DataExample other = (DataExample)o;
if(!other.canEqual(this)) {return false;} else {Object this$name = this.getName();
Object other$name = other.getName();
if(this$name == null) {if(other$name == null) {return this.getAge() != other.getAge()?false:(Double.compare(this.getScore(), other.getScore())!= 0?false:Arrays.deepEquals(this.getTags(), other.getTags()));}
} else if(this$name.equals(other$name)) {return this.getAge() != other.getAge()?false:(Double.compare(this.getScore(), other.getScore())!= 0?false:Arrays.deepEquals(this.getTags(), other.getTags()));}
return false;
}
}
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null?43:$name.hashCode());
result = result * 59 + this.getAge();
long $score = Double.doubleToLongBits(this.getScore());
result = result * 59 + (int)($score >>> 32 ^ $score);
result = result * 59 + Arrays.deepHashCode(this.getTags());
return result;
}
public String toString() {return "DataExample(name=" + this.getName() + ", age=" + this.getAge()+ ", score=" + this.getScore() + ", tags=" + Arrays.deepToString(this.getTags()) + ")";}
}
想必大家现在已经感受到了 lombok 的魅力了吧?如果还没有,别急,这只是刚开始,接着往下看:
# @Getter & @Setter
这两个注解是生成 get、set 方法的,可以写在类上,也可以写在属性上。这两个注解有一个重要的属性 value
, 用来控制生成的方法的访问级别,对应值是 AccessLevel 类型枚举,分别有 PUBLIC, PROTECTED, PACKAGE, 和 PRIVATE,默认为 PUBLIC。
- 源文件
public class Example {
@Getter @Setter private int age = 10;
@Setter(AccessLevel.PROTECTED) private String name;
}
- 字节码文件
public class Example {
private int age = 10;
private String name;
public DataExample(){}
public int getAge() {return this.age;}
public void setAge(int age) {this.age = age;}
protected void setName(String name) {this.name = name;}
}
# @ToString
覆盖默认 toString()
方法。其中常用参数介绍:
- includeFieldNames:生成的 toString() 方法是否包含字段名,布尔类型。
- exclude:不显示在 toString() 中的字段,String 数组。
- callSuper:调用父类 toString(),布尔类型。
- 源码
import lombok.ToString;
@ToString(exclude="id")
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {return this.getName();
}
@ToString(callSuper=true, includeFieldNames=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
- 字节码(部分)
import java.util.Arrays;
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {return this.getName();
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override public String toString() {return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";}
}
@Override public String toString() {return "ToStringExample(" + this.getName() + "," + this.shape + "," + Arrays.deepToString(this.tags) + ")";}
}
# @EqualsAndHashCode
生成 equals 和 hashCode 方法,callSuper 及 exclude 等参数同 @ToString
。
# @RequiredArgsConstructor
作用同注解名,生成必须的构造器,即:无参构造器,若类中用 final
标记的字段,则生成的是包含所有 final 类型字段的构造器。
# @NoArgsConstructor & @AllArgsConstructor
无参构造器及全参构造器。注解参数同 @RequiredArgsConstructor。
# @NonNull
一般写在方法签名中,被此注解的字段,传入值禁止为 null
,否则抛 NPE(NullPointerException)
。
# @Cleanup
被此注解标记的对象,在使用完毕后自动调用对象 close()
方法。
- 源文件
@Cleanup InputStream in = new FileInputStream("some/file");
- 字节码
InputStream in = new FileInputStream("some/file");
try {
// do something
} finally {
if (in != null) in.close();
}
# @Log & @Slf4j & @CommonsLog & @JBossLog 等
注解在类上,在类中自动生成一个属性名为 log
的日志对象,无需再写类似如下代码:
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
# @Builder
生成链式构造,可与 @Data 等注解共存。
User user = User.builder()
.name("xxx")
.age(8)
.phone("13579246810")
.build();
# 结束语
lombok 的能力可不止这些,暂时就介绍这么多吧,如果想知道更多有关信息,请访问: