松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot Vue 微人事视频教程
工作原因,最近我也用上了 Lombok(本文纯属技术探讨,不持任何立场,请轻喷)。
用 Lombok 要在 IDEA 上安装插件,忽然发现我的 IDEA 上不知道啥时候已经安装了这个插件了,仔细回忆,想起来是某一次从网上下载了一个开源项目,对方使用了 Lombok,导致我在本地不得不安装一个 Lombok 插件,这种感觉并不太爽,自那以后这个插件就在我的 IDEA 里躺尸了。
最近没办法,有一个项目一开始就用了 Lombok,我现在接手也不得不用,那么刚好趁此机会,松哥也来和大家聊一聊 Lombok 的使用吧。
Lombok 简介
Lombok 是一个 Java 库,能自动插入编辑器并构建工具,简化 Java 开发。通过添加注解的方式,不需要为类编写 getter/setter/equals 等方法,同时可以自动化日志变量。简而言之:Lombok 能以简单的注解形式来简化 Java 代码,提高开发人员的开发效率。
插件安装
由于 Lombok 会自动帮我们生成一些代码,这些代码在 source 阶段是没有的,编译之后才会用,为了避免开发工具如 IDEA 报错,一般在使用 Lombok 的时候还需要安装一个 IDEA 插件。
安装方式非常简单,直接在 IDEA 市场搜索 Lombok,点击 install 按钮即可,安装完成后,重启 IDEA。
我这个因为安装的比较早,现在已经需要更新了。
具体用法
Lombok 的使用非常简单,在 Spring Boot 创建的时候,就可以添加 Lombok 依赖,如下:
创建成功后,项目中多了如下依赖:
代码语言:javascript复制<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
这就可以了,接下来我们就可以在项目中使用 Lombok 了。
Lombok 主要包含如下一些内容:
- val:类似于前端 js 中的 var。
- @NotNull:这个用于方法参数,可以自动校验方法参数是否为空。
- @Cleanup:这个用在局部变量上,在变量使用结束时会自动调用 close 方法释放资源,典型用法就是 IO 流的相关操作中使用该注解。
- @Getter 用在字段或者类上,当用在字段上时会自动生成字段的 getter;当用在类上时,会自动生成该类所有非静态字段的 getter,使用该注解还可以调整 getter 方法的访问级别。
- @Setter:同上。
- @ToString:这个注解用在类上,自动生成类的 toString 方法,可以做一些定制,比如不使用某个字段,不调用 getter 等。
- @EqualsAndHashCode:这个注解用在类上,自动生成类中所有非静态非瞬时字段(添加了
@Transient
注解的字段为瞬时字段)的 equals 方法和 hashCode 方法。 - @NoArgsConstructor:这个注解用在类上,会自动生成一个无参构造函数。
- @AllArgsConstructor:这个注解用在类上,会自动生成一个包含所有参数的构造函数。
- @RequiredArgsConstructor:这个注解也是作用在类上,它会为 final 字段和标记了 @NotNull 的字段生成构造函数。
- @Data:这个注解也是用在类上,使用该注解相当于同时应用了
@Getter
、@Setter
、@ToString
、@EqualsAndHashCode
、@RequiredArgsConstructor
。如果已经定义了一个构造方法,就不会再自动生成构造方法了。 - @Value:这个注解用在类上,和 @Data 类似,但是用于不可变类型。生成的类和所有字段都设置为 final,所有字段都为 private,自动生成 Getter 但是没有 Setter,会生成初始化所有字段的构造函数。相当于同时应用了
final @ToString
、@EqualsAndHashCode
、@AllArgsConstructor
、@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
和@Getter
。 - @CommonsLog:日志注解,相当于定义变量
log = org.apache.commons.logging.LogFactory.getLog(LogExample.class)
。 - @JBossLog:日志注解:相当于定义变量
log = org.jboss.logging.Logger.getLogger(LogExample.class)
。 - @Log:日志注解,相当于定义变量
log = java.util.logging.Logger.getLogger(LogExample.class.getName())
。 - @Log4j:日志注解,相当于定义变量
log = org.apache.log4j.Logger.getLogger(LogExample.class)
。 - @Log4j2:日志注解,相当于定义变量
log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class)
。 - @Slf4j:日志注解,相当于定义变量
log = org.slf4j.LoggerFactory.getLogger(LogExample.class)
。 - @XSlf4j:日志注解,相当于定义变量
log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class)
。
随便举几个例子大家来感受下。
如下代码:
代码语言:javascript复制@Getter
@Setter
public class User {
private Long id;
private String name;
}
编译结果如下:
如下代码:
代码语言:javascript复制@Data
public class User {
private Long id;
private String name;
}
编译结果如下:
代码语言:javascript复制public class User {
private Long id;
private String name;
public User() {
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void setId(final Long 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 User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id != null) {
return false;
}
} else if (!this$id.equals(other$id)) {
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(final 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 $name = this.getName();
result = result * 59 ($name == null ? 43 : $name.hashCode());
return result;
}
public String toString() {
return "User(id=" this.getId() ", name=" this.getName() ")";
}
}
如下代码:
代码语言:javascript复制public class FileUtils {
public void copy(String source, String dest) throws IOException {
File sourceFile = new File(source);
File destFile = new File(dest);
@Cleanup InputStream in = new FileInputStream(sourceFile);
@Cleanup OutputStream out = new FileOutputStream(destFile);
byte[] b = new byte[1024];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
}
编译后生成的代码如下:
代码语言:javascript复制public class FileUtils {
public FileUtils() {
}
public void copy(String source, String dest) throws IOException {
File sourceFile = new File(source);
File destFile = new File(dest);
FileInputStream in = new FileInputStream(sourceFile);
try {
FileOutputStream out = new FileOutputStream(destFile);
try {
byte[] b = new byte[1024];
while(true) {
int r = in.read(b);
if (r == -1) {
return;
}
out.write(b, 0, r);
}
} finally {
if (Collections.singletonList(out).get(0) != null) {
out.close();
}
}
} finally {
if (Collections.singletonList(in).get(0) != null) {
in.close();
}
}
}
}
我就不一一举例了,这个东西使用还是非常容易的。
小结
Lombok 这个插件还是比较好玩的,注意我用“好玩”来形容它,因为确实好玩,几个注解就可以帮我们生成一大堆代码,N 年前我搞 Android 开发那会,当时 Android 生态里边就有类似的框架,因为当时公司禁止使用该类框架,导致我一直对这种自动生成代码的框架敬而远之。后来搞 Java 了,偶尔也会有小伙伴问我用不用 Lombok,你说不用吧,被说人老古董,你说用吧,被人说是菜鸟,算了,还是沉默吧。
问一个 Java 程序员用不用 Lombok 就像问一个软件工程师哪种开发语言最好,这绝对是一个足够“燃”的话题。但是退一步想想,语言只是一个工具,利用这样一个工具帮助我们实现心中的一些想法才是最重要的,所以没有必要去争论语言的好坏,存在即合理,去争论语言的好坏格局就小了,更何况 Lombok 只是 Java 语言中一个小小的框架。
所以,以后大家见到有人用 Lombok,一定要凑上前说一句:牛逼!见到有人喷 Lombok,也要来一句:牛逼!