Lombok详解

  • Post author:
  • Post category:其他




网上看到这篇文章,这里记录学习一下。


用🌶Lombok,让 Java 更简洁 – ENCODE the WORLD

零、 历史

一个标准的 Java bean。一个典型的 Java bean 一般具有几个属性。每个属性具有一个

accessor



mutator



getter



setter

)。通常还会有一个

toString()

方法、一个

equals()

方法和一个

hashCode()

方法。初看上去,其中可预见的冗余就已经非常多了。如果每个属性都具有一个 getter 和 setter,并且通常如此。

一、 概述



Lombok是一个可以大幅减少java模板代码的工具


二、 使用

onX

Sup dawg, we heard you like annotations, so we put annotations in your annotations so you can annotate while you’re annotating.

呦呵,我们听说你喜欢注解,所以我们将直接放入您的注解使得您可以在注解的时候注解你的方法。



  • JDK7 使用

    onMethod=@__({@xxx})




  • JDK8 使用

    onMethod_={@xxx}


这个方法是实验性的,因为不符合规范,仅仅用来解决不得不在其上加注释的问题。

val

使用位置

局部变量、ForEach

使用

val

可以作为局部变量和foreach循环的类型,它会执行类型推断,从初始化表达式推断出该变量的类型。

对于复合类型表达式如

bool ? new HashSet() : new ArrayList()

, 结果又是

AbstractCollection

又是

Serializable

, 推断的类型将是

AbstractCollection

。因为它是类。

如果很模糊的话 如

null

则为

Object

var

非final本地变量的类型推断,在JEP286中建立了规范,它的工作原理与

val

完全相同,只是不是

final

的。

@NonNull

使用位置:

字段、方法、参数列表



该注解会在方法的顶部添加空指针检查


。如果是空的话,抛出

NullPointerException("param is marked @NonNull but is null");

。在字段上使用时会生成一个包含该字段的构造器,它的get方法以及构造方法都会进行空指针检查。

会在方法的最顶部生成,如果是构造器,会在

super()



this()

之后生成检查方法。如果在方法的顶部已经有非空检查了,那么就不会创建。判断方法请查看官方文档。

@NonNull也有文档角色的概念,不再会产生警告,您可以将方法注解为@NonNull;这是允许的,不产生警告,也不生成任何代码。基本类型参数上的@NonNull会产生警告。不会生成空检查

可配置项

配置项 默认值 可用值 描述

lombok.nonNull.exceptionType

NullPointerException


NullPointerException


|IllegalArgumentException


|Assertion

指定IF中抛出的异常

@Cleanup

使用位置:局部变量

可填写的值 类型 默认值 描述
value
String

close
关闭资源时需要调用的方法名称,该方法必须无参。


使用该注解以确保在代码执行路径退出当前范围之前自动清理给定资源,可注释在任何变量上

默认情况下会进行推断。有参的构造方法无法调用。

@Getter/@Setter

使用位置:类、字段



该注解会为标注的类、字段生成

get/set

方法,并且生成的方法名为驼峰命名法


刁钻的变量起名方式。。。


// 完蛋的起法


String name;


String naMe;


String nAME;

可以通过指定访问级别

AccessLevel

来控制生成的

Getter



Setter

的访问权限。


合法访问级别为

PUBLIC



PROTECTED



PACKAGE



PRIVATE



。也可以使用

None

来禁用

getter



setter

的生成。

可以通过设置

onMethod=@__({@Annotations})



onParam=@__({@AnnotationsHere})

来规定注释在生成的方法上和字段上的注解。



对于以 is 开头且后面紧跟着大写字母的布尔字段,不会添加任何前缀来生成getter名称


。@Getter 也可用于枚举。@Setter 不能用于枚举。

可配置项

配置项 默认值 可用值 描述

lombok.accessors.chain

false

true|false

true

,则生成的setter将返回

this

(而不是

void

)。

@Accessors

注解的显式配置的

chain

参数优先于此设置

lombok.accessors.fluent

false

true|false
生成的getter和setter不会以bean标准

get



is



set

为前缀,会和属性名一样

lombok.accessors.prefix+=/-=
空列表 字段前缀 可以使用

+=

添加前缀,或者使用

-=

删除前缀

lombok.getter.noIsPrefix

false

true|false
为布尔字段生成的 getter 将使用

get

前缀而不是默认的

is

前缀,并且任何调用 getter 的生成代码, 如

@ToString

, 也将使用

get

而不是

is

lombok.copyableAnnotations
空列表 [完全限定类型列表] 会将任何这些注解从字段复制到setter参数和getter方法。

@ToString

使用位置:类

可以生成一个字符串:它会按顺序打印你的类名称以及每个字段,并以逗号分隔,


默认情况会打印所有的非静态字段


,也可通过配置来打印其他字段。

可填写的值 类型 默认值 描述
includeFieldNames
boolean

true
在打印时包括每个字段的名称
@Exclude 字段 在字段上标注以排除这个字段
@Include 字段、方法 在字段上标注以包括这个字段,可以标记方法,使用方法的返回值参与计算
callSuper
boolean

false
在输出中包含父类的结果
doNotUseGetters
boolean

false
调用/不调用

getters

方法
onlyExplicitlyIncluded
boolean

false
仅有显示注释包含的才会输出
exclude
String[]

{""}
这里列出的任何字段将不会被打印在生成的

toString

实现中。
of
String[]

{""}
如果存在,明确列出要打印的字段
  1. 如果有

    toString

    签名的方法,则不会生成额外的方法。
  2. 数组会通过

    Arrays.deepToString

    打印,如果包含自身,会导致栈溢出
  3. 在一个方法上同时加上

    @ToString.Exclude



    @ToString.Include

    , 这种情况会被排除
  4. 默认情况下,

    $

    开头的字段会被忽略,只能通过

    @ToString.Include

    手动包含
  5. 可用于枚举

可配置项

配置项 默认值 可用值 描述

lombok.toString.includeFieldNames

true

true|false
设置为

false

,则

lombok

将省略该字段的名称,只需打印所有字段值的逗号分隔列表。如果明确指定,注解参数

includeFieldNames

优先于此设置。

lombok.toString.doNotUseGetters

false

true|false
如果设置为

true

,则在生成

toString

方法时,

lombok

将直接访问字段,而不是使用getter(如果可用)。如果明确指定,注释参数

doNotUseGetters

优先于此设置。

lombok.toString.callSuper

skip

[ call | skip | warn ]
1.

call

:会调用父类

toString


2.

skip

:不会调用父类

3.

warn



lombok

会警告你

@EqualsAndHashCode

使用位置:类

可以使用字段为该类生成

Equals



HashCode

方法。

可填写的值 类型 默认值 描述
callSuper
boolean

false
@Exclude 字段 在字段上标注以排除这个字段
@Include 字段、方法 在字段上标注以包括这个字段,可以标记方法,使用方法的返回值参与计算
doNotUseGetters
boolean

false
调用/不调用

getters

方法
onParam
AnyAnnotation[]

{}
规定注释在生成的方法上和字段上的注解
onlyExplicitlyIncluded
boolean

false
仅有显示注释包含的才会参与计算
exclude
String[]

{""}
这里列出的任何字段将不会被包含
of
String[]

{""}
如果存在,明确列出要参与计算的字段
  1. 默认情况下,它将使用所有非静态,非瞬时的字段来计算
  2. 默认该注解不会使用超类的

    Equals



    HashCode

    ,可以通过

    callSuper=true

    来显式的调用超类的方法。可能会有某些自定义的

    Equals

    方法会造成意料外的效果,但是由

    lombok

    生成的

    hashCode



    equals

    方法没有这个缺陷。所以推荐仅在子类无继承和

    lombok

    生成的方法上使用

    callSuper

  3. TODO
  4. 数组会通过

    Arrays.deepEquals



    Arrays.deepHashCode

    计算,所以包含自身的数组会导致栈溢出

  5. NaN = NaN
  6. 如果已经有

    hashCode



    equals

    方法,则该注解无论如何都不会生效
  7. 如果方法标记为包含该字段的方法,则方法会覆盖字段。
  8. 默认情况下,

    $

    开头的字段会被忽略,只能通过

    @EqualsAndHashCode.Include

    手动包含

可配置项

配置项 默认值 可用值 描述

lombok.toString.doNotUseGetters

false

true|false
如果设置为

true

,则在生成

equals



hashCode

方法时,

lombok

将直接访问字段,而不是使用

getter

(如果可用)。如果明确指定,注释参数

doNotUseGetters

优先于此设置。

lombok.equalsAndHashCode.callSuper

warn

[ call | skip | warn ]
1.

call

:会调用父类

toString


2.

skip

:不会调用父类

3.

warn



lombok

会警告你

@XxxConstructor

使用位置:类

可以使用字段为该类生成各种各样的

Constructor

可填写的值 类型 默认值 描述
staticName
String

""
静态工厂方法
onConstructor
AnyAnnotation[]

{}
规定注释在生成的构造器上的注解
access
AccessLevel

lombok.AccessLevel.PUBLIC
访问等级
@任意注解 注解

  • staticName

    生成的静态工厂方法拥有自动的类型推断,省去自己写反省的尴尬场景。使用该属性会使得构造方法变为私有的。

@NoArgsConstructor

为类生成无参的构造函数

可填写的值 类型 默认值 描述
force
boolean

false
使用

0

/

false

/

null

初始化所有

final

字段
  1. 标记为

    force=true

    时约束字段不会生成任何检查
  2. 某些框架需要使用无参构造器,该注解主要用来配合

    @Data

    或其他生成构造器的注解使用。

@RequiredArgsConstructor

为每个需要特殊处理的字段生成一个带有对应参数的构造函数。

所有未初始化的

final

字段,以及未初始化的用

@NonNull

标记的字段,都会获得一个参数。对于标有

@NonNull

的字段,还会生成显式空检查

@AllArgsConstructor

为类中的每个字段生成对应参数的构造函数。标有

@NonNull

的字段会导致对这些参数进行空检查

可配置项

配置项 默认值 可用值 描述

lombok.anyConstructor.addConstructorProperties

false

true | false
如果设置为

true

,则 Lombok 将向生成的构造函数添加

@ java.beans.ConstructorProperties

lombok.[allArgsConstructor | requiredArgsConstructor | noArgsConstructor] .flagUsage
未设置
warning|error
配置后,Lombok 将标记相关注解的任何用法为警告或错误

lombok.anyConstructor.flagUsage
未设置
warning|error
配置后,Lombok 将标记所有构造器注解的任何用法为警告或错

注意

显示的构造函数

不会阻止

注解生成自己的构造函数。如果出现冲突,则会出现编译器错误

@Data

使用位置:类

大融合!将

@ToString

,

@EqualsAndHashCode

, 所有字段的

Getter

, 所有非 final 字段的

@Setter

以及

@RequiredArgsConstructor

!它通常用来生成简单的

POJO



Bean

可填写的值 类型 默认值 描述

staticConstructor

String

""
静态工厂方法,等价于

staticName
  • 无法使用

    callSuper

    等参数,如果需要使用,就需要显示的使用注解覆盖。
  • 所生成的

    getter



    setter

    都是私有的,要覆盖需要再写

  • hashCode



    equals

    会跳过静态字段和

    transient

    字段。


  • @RequiredConstructor

    不同,任何构造函数都会阻止

    @Data

    生成构造函数。
  • 任何显式的

    equals



    getter



    setter



    toString

    方法都会阻止生成这些方法,对于

    equals

    ,不同类型的签名也不会生成。
配置项 默认值 可用值 描述

lombok.data.flagUsage
未设置
warning|error
配置后,Lombok 将标记所有构造器注解的任何用法为警告或错误

@Value

使用位置:类



@Data

的不可变形式,相当于为属性添加final声明,只提供getter方法,而不提供setter方法

  • 等价于

    final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter
  • 所有字段都是

    private final

  • 可使用

    @NonFinal

    来去掉

    final
  • 默认类本身也是

    final

  • 生成一个覆盖每个参数的构造函数(除显式初始化的字段外)

@Builder

使用位置:类、方法、构造器

提供复杂的

builder APIs

可填写的值 类型 默认值 描述

builderMethodName

String

"builder"
builder 方法的名称

buildMethodName

String

"build"
build 方法的名称

builderClassName

String

""
构造器的类名

toBuilder

boolean

false
生成一个在类中的

toBuilder

方法,返回包含当前类所有字段的

Builder

access

AccessLevel

PUBLIC
生成元素的访问级别

setterPrefix

String

""

setter

的前缀名

@Builder 后的方法

  1. 一个名为

    FooBuilder

    的内部静态类,与静态方法(称为builder)具有相同的类型参数。
  2. 静态类中:一个non-static no-final字段对应目标的一个参数
  3. 静态类中:一个私有的不带参数的空构造函数
  4. 静态类中:外部类的每个参数会获得一个类型和字段名都相同的类似

    setter

    的方法,返回构造器本身以供链式处理
  5. 静态类中:一个

    build

    方法,调用外部的构造方法,传入每个参数。
  6. 静态类中:一个

    toString

    方法
  7. 外部类中:

    builder()

    方法,返回构造器的实例

若上述内容已存在(只管方法名),则将跳过。

@Builder 后的类

效果类似于

@AllArgsConstructor(access = AccessLevel.PACKAGE)

。如果有一个构造器,应该将

@Builder

放在构造器上

@Builder.Default

如果在

build

期间没有设置属性的任何值的化,它的值会为

0/null/false

,可以在字段上添加

@Builder.Default

注释

@Builder.ObtainVia

使用位置:字段、参数

如果开启了

toBuilder

方法的生成,可以规定所属字段(参数)如何获取值,默认为通过

this.xxx

来获取

  • 指定字段获取值

    this.value
  • 指定方法获取值

    this.method()
  • 指定通过静态方法获取值

    类.method(this)

@Singular

使用此注解可以注释一个集合字段(参数)

  1. 会生成两个方法:

    • 一个用于添加一个元素到集合中
    • 用于将另一集合中的所有元素添加到集合中。
  2. 生成

    clearXxx

    方法,用于清空集合。

拥有该注解后的构造器非常的复杂,以满足以下条件

  1. 调用

    build()

    时集合不可变

  2. build()

    之后调用添加或删除方法不会修改生成的对象
  3. 生成的集合将被压缩

只能支持有限的类型,

List



Map



Set

是其中较为典型的类型

如果注解不能单数化你的字段名,它将报错并要求你指定单数的名称

注意


  1. @Builder.Default

    字段上的初始化程序将在编译过程中移动并存储在静态方法中,以确保在构建有值时不会执行该方法
  2. 可将

    builderMethodName

    配置为空字符串,这将阻止

    builder()

    方法的生成
  3. 上述特性可用于

    toBuilder().build()

    实现浅拷贝。

可配置项

配置项 默认值 可用值 描述

lombok.data.flagUsage
未设置
warning|error
配置后,Lombok 将标记所有构造器注解的任何用法为警告或错误

lombok.singular.useGuava

false

true|false
是否使用

guava

的构造器实现

java.util

接口

lombok.singular.auto

true

true|false
如果为

true



lombok

会自动尝试通过假设它是一个常见的英语复数来单数化你的标识符名称。如果为

false

,则必须始终显式指定单数名称

@SneakyThrows

使用位置:方法、构造器

偷偷的抛出某些异常而不在方法上声明

throws

,需要谨慎使用。实际上它时欺骗了编译器。原理是在 JVM 级别上,无论如何都可以抛出以常。

可填写的值 类型 默认值 描述

value

Class<? extends Throwable>[]

java.lang.Throwable.class
偷偷抛出的方法名称

常见使用情况

  • 一个不必要的严格接口,

    Runnable

    无论是否抛出异常,它都将被传递给

    Thread
  • 一个不可能的异常,如:

    new String(SomeByteArray, "UTF-8")

    声明其可抛出

    UnsupportedEncodingException

    ,但是根据JVM规范,UTF-8必须始终可用。这里的

    UnsupportedEncodingException

    与使用String对象时的

    ClassNotFoundError

    差不多,你也没有必要捕获这些不可能的异常

注意

在被抛出后就不能捕获了,因为编译器不允许你为

try

体中没有方法声明抛出的异常类型编写对应的

catch

@Synchronized

使用位置:方法



synchronized

方法修饰符的更安全变体,与

synchronized

方法修饰符相似,只能用在静态方法上。

synchronized

锁定在

this

上,而注解锁定在

$LOCK

的静态字段。

可填写的值 类型 默认值 描述

value

String

""
选择锁定的字段名

可以自行创建

$lock



$LOCK

字段。

本注解的作用是:锁定

this

和类对象可能会产生一些副作用,因为其他人也能锁定这些对象,这样可能会导致竞争和其他讨厌的线程错误。

注意

  • 自动生成的

    $lock



    $LOCK

    会使用

    Object[]

    数组初始化字段,

    Lombok

    这样做是因为

    new Object()

    不可序列化,但是大小为0的数组可以序列化,使用

    @Synchronized

    不会阻止对象序列化
  • 类中至少有一个

    @Synchronized

    方法意味着会有一个锁定字段,但是如果稍后删除所有这些方法,则不再有锁定字段。这意味着你预定的

    serialVersionUID

    会发生变化

@With

使用位置:字段、类

用于生成一个

withX(T newValue)

方法,该方法判断传入值和原有值是否相等,不相等会返回一个其他字段都相同的新对象。

比如说,为

final

字段设置

setter

是没有意义的,name,使用

@With

是很好的办法,

可填写的值 类型 默认值 描述

value

AccessLevel

false
生成方法的访问类型

onMethod

With.AnyAnnotation[]

{}
在方法上生成的注解

onParam

With.AnyAnnotation[]

{}
在参数上生成的注解

注意事项

  • 该注解完全依赖构造方法克隆对象,所以要确保游泳构造方法
  • 静态字段无法生成方法,因为没有任何意义
  • 抽象类可用,会生成拥有适当签名的抽象方法
  • 会跳过所有

    $

    开头的字段
  • 同名方法会覆盖

@Getter(lazy=true)

使用位置:字段

可以让

Lombok

生成一个

getter

, 在第一次调用时会计算一次,之后缓存起来,如果计算该值需要占用大量 CPU,或者大量内存,则非常有用。

  1. 创建一个

    private final

    的变量
  2. 使用

    @Getter(lazy=true)

    注释字段

就算你的值为

null

,也会被缓存,并且

Lombok

会为该方法加锁。

注意

  • 永远要使用

    getter

    访问字段,因为它是

    AtomicReference

    的,而且你无法分辨结果为

    null

    时到底为计算还是未计算。
  • 即使你使用

    doNotUseGetters=true

    ,其他 Lombok 注释(如

    @ToString

    )也始终调用 getter

@Log

使用位置:类

它将为你生成一个

static final log = 你的类名

字段

注解类型 对应

Log


@CommonsLog

org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Flogger

com.google.common.flogger.FluentLogger.forEnclosingClass();

@JBossLog

org.jboss.logging.Logger.getLogger(LogExample.class);

@Log

java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j

org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2

org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j

org.slf4j.LoggerFactory.getLogger(LogExample.class);

@XSlf4j

org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
可填写的值 类型 默认值 描述

topic

String

""

代表当前类

Logger

的主题/名称

可配置项

配置项 默认值 可用值 描述

lombok.data.flagUsage
未设置
warning|error
配置后,Lombok 将标记所有注解的任何用法为警告或错误

lombok.log.fieldName

log
其他名字 生成的

logger

字段名称

lombok.log.fieldIsStatic

true

true| false
生成的记录器logger是

static

字段。通过将此键设置为

false

,生成的字段将是实例字段

lombok.log.xxxxxx.flagUsage
未设置
warning|error
配置后,Lombok 将标记所有注解的任何用法为警告或错误

注意事项

  • 如果已存在名为

    log

    的字段,则将发出警告,并且不会生成任何代码。

experimental

实验字段们,可以正常使用,但没有主要功能那么强大的支持。以下的注解意味着

  • 没有经过完整测试
  • 不会像核心功能那样快速修复错误
  • 可能会发生变更
  • 可能会完全消失
  • 社区反馈积极的且看起来没有那么大破坏性,则可能会被接收为核心功能
注解 作用 当前状态

var
本地变量,通过类型推断分配值

@Accessors
支持三种模式

1.

fluent

:

getter



setter

的方法都是属性名,并且

setter

返回当前对象

2.

chain



setter

对象返回当前对象

3.

prefix

: 用于忽视指定前缀,如 字段中带

master_

,则可忽略为本身字段名

中性

@ExtensionMethod
可以包含一些方法到类中,使得其像实例方法一样使用。
保持

@FieldDefaults
通过该注解控制一些访问修饰符和访问级别
积极

@Delegate
将某些访问指定类、字段的调用重定向到该字段上
消极

onX
在最开始有所介绍
不确定

@UtilityClass
表示该类是工具类,不存在任何实例,自动为该类生成一个私有构造器并在被调用时抛出异常。将所有的成员都自动转换为

static

积极

@Helper
允许将方法放入方法,而不需要实例化内部类,直接调用
未知

@FieldNameConstants
为类生成一个包含所有字段字段名的静态内部类
中性

@SuperBuilder
为父类生成一个

builder

@Tolerate
可在任何字段和方法标注,使

Lombok

忽略这些字段,例如本来

Lombok

认为已经有并且不再生成的方法,可以让其忽略并生成

@Jacksonized


Jackson

准备的注解,自动配置生成的

Builder

用于

Jackson

的反序列化

三、Lombok配置

灵活的配置每个

Lombok

的配置项

  1. 可以在任何目录中创建。作用于该目录和其子目录

  2. lombok.config

    中配置项

    config.stopBubbling=true

    指明

    lombok

    的根目录为当前配置文件所在目录
  3. 配置文件是分层的,原则是接近源文件的配置设置优先
  4. 根目录的子目录中可以创建

    lombok.config

    配置文件,来覆盖根目录的配置文件
  5. 在配置文件的顶部,可以导入其他配置文件。

    import ../conf/aaa.config

四、DeLombok


使用

Delombok

命令把

Lombok

注解实现的类文件转换为不使用

Lombok



Java

源文件

。如果是

src

整个目录,可以递归的实现转换,

Delombok

会自动过滤非

Lombok

注解的文件进行原样拷贝。

不仅可以了解到 Lombok 的实现内幕,还可以很好的做系统升级,比如要生成

javadoc

或者使用

Google Widget Toolkit

都是不支持

Lombok

的,这时候就可以使用

Delombok

进行反编译,同时也能解决我们使用

Lombok

升级

JDK

带来的不兼容问题。

五、Lombok深入

5.1 Lombok 是怎么实现的

lombok是通过什么来实现在编译时的?


通过

JSR 269: Pluggable Annotation Processing API

(Java 规范提案)

通过分析和置换抽象语法树所生成全新的字节码




Javac





解析成抽象语法树之后(

AST

),

Lombok

根据自己的注解处理器,动态的修改

AST

,增加新的节点(所谓代码),最终通过分析和生成字节码。

5.2 Lombok 扩展

六、一些坏处

  1. 使用

    Lombok

    会强行使别人也需要安装

    Lombok

    插件,否则到处报错,不过现在

    IDEA

    已经内置支持了

    Lombok

    ,如果我们定义的一个jar包中使用了Lombok,那么就要求所有依赖这个jar包的所有应用都必须安装插件,这种侵入性是很高的。
  2. 代码可读性,可调试性低

  3. 影响升级,

    Lombok

    对于代码有很强的侵入性,就可能带来一个比较大的问题,那就是会影响我们对JDK的升级。每次大升级都会使 一大票使用

    Lombok

    的发出哀嚎。

  4. Lombok

    自身的升级也会受到限制,而每个

    jar

    包可能又要依赖不同版本的

    Lombok

    ,这就导致在应用中需要做版本仲裁,

    jar

    包版本仲裁是没那么容易的,而且发生问题的概率也很高。
  5. 破坏封装性,无脑使用

    getter



    setter

    不如不使用。
  6. 而其个类如果有嵌套引用,不做特殊处理,序列化的时候会死循环。


  7. Lombok

    违反了

    Java annotation processor

    的规定,使用 HACK 字节码的方式实现这些方法,可能会导致一些不好发现的问题,在多个

    JVM

    语言混用时容易出一些离奇的错误

七、拓展延伸

其于主流的代码生成工具


  1. AutoValue

    • 谷歌出品
    • 生成

      Java源文件

  2. Immutables

    • 支持的特性较多
    • 提供了与

      AutoValue

      类似的功能,并添加了使用

      @value.modiizable

      生成可修改类的功能
对比项 Lombok AautoValue Immutables
License MIT (also) Apache 2 Apache 2
最低java版本 1.6 1.6 1.7
生成的文件 lombok修改了原class文件,加入生成的代码 生成了另外一个java子类,不侵入原有的java代码,完全遵循java的规范,可以看到两个java文件和两个class文件 生成了另外一个java子类,不侵入原有的java代码,完全遵循java的规范,可以看到两个java文件和两个class文件
生成类与模版类关系 Enhanced generated class replaces template source Generated source extends template source Generated source extends template source
查看生成类 使用delombok 默认可见 默认可见
使用方便性 为类或字段添加注解即可 加上注解的同时,需要按照一定的规范遍写代码 加上注解的同时,需要按照一定的规范遍写代码
是否需要提前编译 不用,加上注解后,就可以用其生成的方法 编译一次,才能生效,编译前是找不到待生成的子类的 编译一次,才能生效,编译前是找不到待生成的子类的
生成的代码是否可见 不可见,实在要看需要反编译,不利于Debug可代码分析比如覆盖率等 可以看见生成的源代码,在代码调试和分析时较方便 可以看见生成的源代码,在代码调试和分析时较方便
不可变程度 可以使用set方法修改类 可以使用Immutability修改类 强支持不可变

如何选择这三个工具

1)AutoValue和Immutables使用标准注释处理,Lombok使用非标准注释处理方法:

  • 开发者如果希望避免非标准依赖,那么应该使用AutoValue和Immutables;
  • 开发者不希望添加IDE插件或者其他非javac以及非基础Java IDE支持的第三方工具,那么建议使用AutoValue和Immutables;

2)Lombok修改了原class文件,生成的类与模版类在同一个包下,并且名字相同;AutoValue和Immutables生成的类继承自基础模版类,但是在同一个包下:

  • 开发者如果希望编译的class文件和源文件在同一个包下,并且同名,那么应该使用Lombok;
  • 开发者如果希望可以看到生成的代码,并且不希望影响原来的代码,那么应该使用AutoValue和immutebles;

3)三个工具都不同程度上的支持自定义,因此和这个需要根据实际需要进行选择:

  • Lombok提供了一个

    configuration system

    ,允许根据所需的约定调整生成代码。
  • Immutables提供了

    style customization

    ,允许对生成的代码的多个点进行调整。
  • AutoValue允许用户通过一些方式

    User Guide

    ,自行定义一些生成代码的规则。

4)从可变性看,三者的opinionated不同,AutoValue是不支持可变的,而Lombok和Immutables支持:

  • 希望类成为不可变类,使用AutoValue;
  • 希望类一定程度上支持可变,那么使用Lombk或者Immutables;

八、 参考文献


  1. 华山论剑之JAVA三大代码生成工具:Lombok、AutoValue和Immutables

    2019.09.18 12:37:07

  2. Project Lombok

    2021.04.19 00:00:00