简介
使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。一些简单的Getter和Setter的确可以借助IDE自动生成,复杂一些注解@Cleanup @Buider @With提供了IDE代码生成不具备的功能,能显著提升开发效率、减少BUG。
maven配置
加入依赖
到2021年8月最新的版本是1.18.20,另外scope是provided,因为lombok是编译时使用的,运行时不需要加载。
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
maven编译配置
lombok是利用编译的时候解析和编辑语法树实现的,所以需要在编译的时候引入配置。maven中需要加入到maven-compiler-plugin里面
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
开发IDE配置
这个就比较简单了,选择相应IDE的插件进行安装就好了,下图以IDEA的Lombok为例。

主要的用法
val/var
您可以使用val作为局部变量声明的类型,而不是实际写入类型。 执行此操作时,将从初始化表达式推断出类型。 本地变量也将成为最终变量。 此功能仅适用于局部变量和foreach循环,而不适用于类属性(field)。 初始化表达式是必需的。val实际上是一种“类型”,在lombok包中作为一个真正的类存在。 您必须导入它才能使val工作(或使用lombok.val作为类型)。 在本地变量声明中存在这种类型会触发添加final关键字以及复制初始化表达式的类型,该类型会覆盖’伪’val类型。
val和var的区别在于,var标记的局部变量并不是final的。
一般情况下我们申明类型,总是需要这么写
// 列表
ArrayList<String> example = new ArrayList<>();
// map
Map<String, Integer> map = new HashMap<>(12);
// java对象
JavaBean bean = new JavaBean();
现在可以通过var进行简化
public class ValExample {
public String example() {
val example = new ArrayList<String>();
example.add("Hello, World!");
val foo = example.get(0);
return foo.toLowerCase();
}
public void example2() {
val map = new HashMap<Integer, String>();
map.put(0, "zero");
map.put(5, "five");
for (val entry : map.entrySet()) {
System.out.printf("%d: %s\\n", entry.getKey(), entry.getValue());
}
}
}
编译以后的代码是
public class ValExample {
public String example() {
final ArrayList<String> example = new ArrayList<String>();
example.add("Hello, World!");
final String foo = example.get(0);
return foo.toLowerCase();
}
public void example2() {
final HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(0, "zero");
map.put(5, "five");
for (final Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.printf("%d: %s\\n", entry.getKey(), entry.getValue());
}
}
}
@Cleanup
自动关闭资源,针对实现了java.io.Closeable接口的对象有效,如:典型的IO流对象。
public class CleanupExample {
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
}
//编译后
public class CleanupExample {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}
}
@NonNull
主要作用于成员变量和参数中,标识不能为空,否则抛出空指针异常。变异以后的代*会码**增加Null的检查。
public class NonNullExample extends Something {
private String name;
public NonNullExample(@NonNull Person person) {
super("Hello");
if (person == null) {
throw new NullPointerException("person is marked @NonNull but is null");
}
this.name = person.getName();
}
}
@Builder用法
@Builder注释为你的类生成相对略微复杂的构建器API。@Builder可以让你以下面显示的那样调用你的代码,来初始化你的实例对象:
Student.builder()
.sno( "001" )
.sname( "admin" )
.sage( 18 )
.sphone( "110" )
.build()
@Builder中使用 @Singular 注释集合
@Builder也可以为集合类型的参数或字段生成一种特殊的方法。 它采用修改列表中一个元素而不是整个列表的方式,可以是增加一个元素,也可以是删除一个元素。
在使用@Singular注释注释一个集合字段(使用@Builder注释类),lombok会将该构建器节点视为一个集合,并生成两个adder方法而不是setter方法。
- 一个向集合添加单个元素
- 一个将另一个集合的所有元素添加到集合中
@Getter 和@Setter
作用在类上,生成所有成员变量的getter/setter方法;作用于成员变量上,生成该成员变量的getter/setter方法。生成的方法默认的public的可以,可以通过设置AccessLevel改变,可选
有。其中NONE,表示不生成Get/Set方法
public enum AccessLevel {
PUBLIC,
MODULE,
PROTECTED,
PACKAGE,
PRIVATE,
NONE;
private AccessLevel() {
}
}
Getter的lazy属性的意思是延迟生效。使用了getter这个annotation可以在实际使用到cached的时候生成cached,同时,Lombok会自动去管理线程安全的问题,不会存在重复赋值的问题。
public class GetterLazyExample {
@Getter(lazy=true) private final double[] cached = expensive();
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
}
@ToString
@ToString:作用于类,覆盖默认的toString()方法,可以通过of属性限定显示某些字段,通过exclude属性排除某些字段。除了加在类上面,还可以加在类属性上面。
@ToString
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
@ToString.Exclude private int id;
public String getName() {
return this.name;
}
@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;
}
}
}
@EqualsAndHashCode
作用于类,覆盖默认的equals和hashCode。不需要的内容可以Exclude掉。
@EqualsAndHashCode
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
@EqualsAndHashCode.Exclude private Shape shape = new Square(5, 10);
private String[] tags;
@EqualsAndHashCode.Exclude private int id;
public String getName() {
return this.name;
}
@EqualsAndHashCode(callSuper=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
@NoArgsConstructor:生成无参构造器;
@RequiredArgsConstructor:生成包含final和@NonNull注解的成员变量的构造器;还可以定义一个staticName用于生成静态的方法。
@AllArgsConstructor:生成全参构造器.
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
private int x, y;
@NonNull private T description;
@NoArgsConstructor
public static class NoArgsExample {
@NonNull private String field;
}
}
@Data
等价于上面的@Setter、@Getter、@RequiredArgsConstructor、@ToString、@EqualsAndHashCode
如果需要对Get/Set方法进行调整,可以增加@Getter和@Setter
@Value
跟@Data类似,只是所有的字段是private和final的。
@SneakyThrows
很多情况下我们遇到异常是向上一抛了之
try{
}catch(Exception e){
throw new RuntimeException(e);
}
//原始代码
public class SneakyThrowsExample implements Runnable {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
@SneakyThrows
public void run() {
throw new Throwable();
}
}
//编译以后的代码
public class SneakyThrowsExample implements Runnable {
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw Lombok.sneakyThrow(e);
}
}
public void run() {
try {
throw new Throwable();
} catch (Throwable t) {
throw Lombok.sneakyThrow(t);
}
}
}
@With
@with的作用是克隆原来的对象,新的对象的字段进行更新。
//编译以前的代码
public class WithExample {
@With(AccessLevel.PROTECTED) @NonNull private final String name;
@With private final int age;
public WithExample(String name, int age) {
if (name == null) throw new NullPointerException();
this.name = name;
this.age = age;
}
}
//编译以后的代码
public class WithExample {
private @NonNull final String name;
private final int age;
public WithExample(String name, int age) {
if (name == null) throw new NullPointerException();
this.name = name;
this.age = age;
}
protected WithExample withName(@NonNull String name) {
if (name == null) throw new java.lang.NullPointerException("name");
return this.name == name ? this : new WithExample(name, age);
}
public WithExample withAge(int age) {
return this.age == age ? this : new WithExample(name, age);
}
}