优质博文:IT-BLOG-CN
一、痛点
【1】代码臃肿:POJO
中的getter/setter/equals/hashcode/toString
等;
【2】样板式代码:I/O
流的关闭操作等;
Lombok
是一个可以通过注解简化Java
代码开发的工具,能够在我们编译源码的时候自动帮我们生成代码,如getter/setter/hashcode
等;
官网
GitHub
二、Lombok 缺点
【1】反射: Lombok
注解处理器在编译期间会生成一些代码,其中包括getter
和setter
方法、构造函数等。这些代码在运行时可以通过反射来访问和调用。使用反射会带来性能问题:反射调用方法的性能通常比直接调用方法要慢得多,因为反射需要进行额外的操作来查找和调用方法。安全问题:反射可以访问和调用私有方法和字段,这可能会导致安全问题。可维护性问题:由于反射调用方法的代码通常比直接调用方法的代码更加复杂,因此可能会导致代码难以理解和维护。
【2】影响升级: Lombok
对于代码有很强的侵入性,就可能带来一个比较大的问题,那就是会影响我们对JDK
的升级。如果我们需要升级到某个新版本的JDK
的时候,若其中的特性在Lombok
中不支持的话就会受到影响。因为一个应用可能依赖了多个jar
包,而每个jar
包可能又要依赖不同版本的Lombok
,这就导致在应用中需要做版本仲裁,而我们知道,jar
包版本仲裁是没那么容易的,而且发生问题的概率也很高。
【3】隐藏的问题: 在使用Lombok
过程中,如果对于各种注解的底层原理不理解的话,很容易产生意想不到的结果。举个例子,当我们使用@Data
定义一个类的时候,会自动帮我们生成equals()
方法。但是如果只使用了@Data
,而不使用@EqualsAndHashCode(callSuper=true)
的话,会默认是@EqualsAndHashCode(callSuper=false)
,这时候生成的equals()
方法只会比较子类的属性,不会考虑从父类继承的属性,无论父类属性访问权限是否开放。所以我们使用工具时,就应该对这个工具有一定了解,不然就变成黑盒了,上线很容易出问题。
【4】代码可读性和可调试性降低: 大量使用Lombok
,例如想要知道某个类中的某个属性的getter
方法都被哪些类引用的话,就没那么简单了。这种说法其实也是不对的,通过IDEA
可以很方便的找到某个属性的getter
方法都被哪些类引用。
【5】必须安装第三方插件: 如果未安装插件,使用IDE
打开一个基于Lombok
的项目的话会提示找不到方法等错误。导致项目编译失败。所以只要你负责的项目使用了Lombok
,就必须安装插件。这点我觉得不是最不能接受的,安装一个插件也不会很费事。
【6】破坏抽象: 如果我们在代码中直接使用Lombok
,那么他会自动帮我们生成getter
、setter
等方法,这就意味着,一个类中的所有参数都自动提供了设置和读取方法。外部可以通过setter
方法随意地修改属性的值。而面向对象封装的定义是:通过访问权限控制,隐藏内部数据,外部仅能通过类提供的有限的接口访问、修改内部数据。所以,暴露不应该暴露的setter
方法,明显违反了面向对象的封装特性。
三、使用
【1】引入POM
依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
【2】安装插件:Perferences->Plugins->Search Lombok plugin->Install
,同时勾选Preferences->Compiler->Annotation Processors->Enable annotation processing
。
【3】常见注解:
@Data // 包含了@ToString、@EqualsAndHashCode、@Getter、@Setter和@RequiredArgsConstructor的功能
@Getter // 生成的get方法是publish
@Getter(lazy = true) // 标注字段为懒加载字段,懒加载字段在创建对象时不会进行初始化,而是在第一次访问的时候才会初始化,后面再次访问也不会重复初始化
@Getter(AccessLevel.PROTECTED) // 生成的get方法是protected
@Setter
@NoArgsConstructor // 生成无参构造器,当有final字段没有被初始化时,编译器会报错。使用@NoArgsConstructor(force = true)时,没有初始化final字段设置默认值 0 / false / null, 这样编译器就不会报错。对于具有约束的字段(例如@NonNull字段),不会生成检查或分配,因此请注意,正确初始化这些字段之前,这些约束无效。
@AllArgsConstructor // 所有参数构造器
@RequiredArgsConstructor // 生成构造方法(可能带参数也可能不带参数),如果带参数,这参数只能是以final修饰的未经初始化的字段,或者是以@NonNull注解的未经初始化的字段。
@RequiredArgsConstructor(staticName = "of") // 会生成一个of()的静态方法,并把构造方法设置为私有的
@NonNull // setter方法执行时,如果传入的参数为Null时,会抛出NPE
@ToString // 生成toString()方法,默认情况下它会按顺序(以逗号分隔)打印你的类名称以及每个字段。可以这样设置不包含哪些字段,可以指定一个也可以指定多个@ToString(exclude = "id") / @ToString(exclude = {"id","name"})。如果继承的有父类的话,可以设置callSuper让其调用父类的toString()方法,例如:@ToString(callSuper = true)
@EqualsAndHashCode // 生成hashCode()和equals()方法,默认情况下,它将使用所有非静态,非transient字段。但可以通过在可选的exclude参数中来排除更多字段。或者,通过在of参数中命名它们来准确指定希望使用哪些字段。
@Value // 将字段都变成不可变类型:使用final修饰, 同时还包含@ToString、@EqualsAndHashCode、@AllArgsConstructor 、@Getter(注意只有Getter没有Setter)
@Log // 生成log对象,用于记录日志,可以通过topic属性来设置getLogger(String name)方法的参数 例如 @Log4j(topic = “com.xxx.entity.User”),默认是类的全限定名,即 类名.class,log支持以下几种:@Log java.util.logging.Logger;@Log4j org.apache.log4j.Logger;@Log4j2 org.apache.logging.log4j.Logger;@Slf4j org.slf4j.Logger;@XSlf4j org.slf4j.ext.XLogger;@CommonsLog org.apache.commons.logging.Log;@JBossLog org.jboss.logging.Logger
@SneakyThrows // 替代 try{}catch(Exception e){}这样的模板代码: @SneakyThrows(InterruptedException.class) 使用在方法上面。
@Synchronized // 给方法加上同步锁。
@Cleanup // 用来修饰 IO 流相关类, 会在 finally 代码块中对该资源进行 close(); 举例:@Cleanup InputStream in = new FileInputStream(args[0])
@Wither // 提供了给final字段赋值的一种方法
@Builder // 为你的类生成复杂的构建器API。
@Delegate // 为List类型的字段生成一大堆常用的方法,其实这些方法都是List中的方法
四 lombok config 文件
lombok.config
配置文件是通过一些设置来控制代码生成的规则或者称之为习惯,配置文件的位置应放在src/mian/java
,不要放置在src/main/resources
。配置文件和要使用注解的类要在同一套代码中,要么同时在src/main/java
要么同时在src/test/java
中。
#lombok 默认对boolean类型字段生成的get方法使用is前缀,通过配置则使用get前缀,默认 false
lombok.getter.noIsPrefix=true
#默认的set方法返回void设置为true返回调用对象本身,这样方便使用链式来继续调用方法,默认:false
lombok.accessors.chain=true
#如果设置为true,get和set方法将不带get和set前缀,直接以字段名为方法名,默认false
lombok.accessors.fluent=true
#设置log类注解返回的字段名称,默认 log
lombok.log.fieldName=logger