最近在公司的项目中看到了对于Lombok的应用,通过@Data注解标注POJO,省略了大量的getter/setter代码,原先冗长的POJO在瘦身之后直接变得干净、清爽,程序员再也不需要去关注那些长长的方法,只需要集中注意力于字段field之中
Lombok简介
Lombok是一个非常实用的Java工具库,有效地简化Java代码的冗长。它通过注解如@Data可以直接为Java bean在编译期动态地生成字段的getter/setter方法,使用注解@NoArgsConstructor 和@AllArgsConstructor 为Java bean添加无参构造器和有参构造器,甚至可以在Java代码中使用val和var声明一个动态变量,而无需再指定具体的变量类型,区别只是val声明的变量为final。
Lombok还提供了delombok供生成Javadoc,delombok在运行时会将注解@Data转换成getter/setter方法,然后移除@Data注解,如果哪天不再需要Lombok,也只需要简单运行delombok即可。Lombok的构建支持maven和gradle,同时eclipse、myeclipse和idea等主流IDE也都和lombok兼容,所以可以放心大胆地使用Lombok,不用担心IDE的编译检查问题。
Lombok栗子
Eclipse安装Lombok支持
官网Lombok https://projectlombok.org/download 下载jar包或者通过构建工具maven,gradle下载jar包
双击jar包,jar包内的安装器会自动运行寻找eclipse
点击【Install/Update】
引入Lombok依赖
<
dependency
>
<
groupId
>
org.projectlombok
groupId
>
<
artifactId
>
lombok
artifactId
>
<
version
>
1.18.2
version
>
<
scope
>
provided
scope
>
dependency
>
Lomok注解使用
Lombok的注解分为稳定版本和试验版本,这里主要介绍稳定版本,因为试验版本的支持目前和IDE不是很好
@Getter/@Setter注解
@Getter/@Setter注解的作用就是为字段添加getter/setter方法,可标注在类上,也可标注在字段上。标注在类上表示所有的非静态(no-static)字段都会生成相应的getter/setter方法,标注在字段上表示只为这个字段生成,且会覆盖标注在类上的注解。可设置访问级别,默认为public。@Setter不可以标注final字段
@Getter
@Setterpublic
class
SetterExample
{
@Getter
(value=AccessLevel.PRIVATE)
@Setter
private
String name;
@Setter
(onMethod=@__({
@Deprecated
}))
private
String age;
@Setter
(onParam=@__({}))
private
String sex;
public
static
void
main
(String[] args)
{
SetterExample se =
new
SetterExample();
se.setName(
"zhangsan"
);
se.setAge(
"16"
);
System.out.println(se.getAge());
System.out.println(se.getName());
}
}
Lombok提供了onX的试验属性,分别为:onMethod, onParam, onConstructor,用于向生成的方法,构造器,参数添加注解
反编译后结果
@NonNull注解
@NonNull注解标注方法和构造器的参数,如果参数为null,则会抛出空指针异常,不需要在代码中进行null检测
public
class
NonNullExample
{
@Getter
private
String name;
public
NonNullExample
(@NonNull String name)
{
this
.name = name;
}
public
static
void
main
(String[] args)
{
String name =
null
;
NonNullExample nne =
new
NonNullExample(name);
System.out.println(nne.getName());
}
}
@ToString注解
@ToString注解生成toString()方法
@ToStringpublic
class
ToStringExample
{
@ToString
.Exclude
private
String name;
@ToString
.Include
private
String age;
private
String sex;
public
static
void
main
(String[] args)
{
ToStringExample tse =
new
ToStringExample();
System.out.println(tse.toString());
}
}
属性includeFieldNames,默认为true,包含属性值
属性callSuper,默认为false,调用父类实现
属性onlyExplicitlyIncluded,默认为false,仅包含明确包含的属性
@ToString.Exclude 标注属性值不包含在toString()方法中
@ToString.Include标注属性值包含在toString()方法中
@EqualsAndHashCode
@EqualsAndHashCode注解生成equals()和hashcode()方法,注解的属性和@ToString类似
@EqualsAndHashCodepublic
class
EqualsAndHashcodeExample
{
private
String name;
private
String age;
private
String sex;
public
static
void
main
(String[] args)
{
EqualsAndHashcodeExample ehe1 =
new
EqualsAndHashcodeExample();
EqualsAndHashcodeExample ehe2 =
new
EqualsAndHashcodeExample();
System.out.println(ehe1.equals(ehe2));
System.out.println(ehe1.hashCode());
System.out.println(ehe2.hashCode());
}
}
@NoArgsConstructor@RequiredArgsConstructor@AllArgsConstructor
@NoArgsConstructor
: 生成一个无参数的构造方法
@NoArgsConstructor
(force=
true
, staticName=
"newInstance"
)
public
class
NoArgsConstructorExample
{
private
final
String name;
@NonNull
@Getter
private
String age;
private
String sex;
public
static
void
main
(String[] args)
{
NoArgsConstructorExample nace1 =
new
NoArgsConstructorExample();
System.out.println(nace1.getAge());
NoArgsConstructorExample nace2 = NoArgsConstructorExample.newInstance();
System.out.println(nace2.getAge());
}
}
@RequiredArgsConstructor
:会生成一个包含常量,和标识了NotNull的变量 的构造方法。
@RequiredArgsConstructor
(staticName=
"newInstance"
)
public
class
RequiredArgsConstructorExample
{
private
final
String name;
@NonNull
@Getter
private
String age;
private
String sex;
public
static
void
main
(String[] args)
{
RequiredArgsConstructorExample race1 =
new
RequiredArgsConstructorExample(
"lisi"
,
"18"
);
System.out.println(race1.getAge());
RequiredArgsConstructorExample race2 = RequiredArgsConstructorExample.newInstance(
"zhangsan"
,
"16"
);
System.out.println(race2.getAge());
}
}
@AllArgsConstructor:会生成一个包含所有变量,同时如果变量使用了NotNull annotation , 会进行是否为空的校验
@AllArgsConstructor
(staticName=
"newInstance"
)
public
class
AllArgsConstructorExample
{
private
final
String name;
@NonNull
@Getter
private
String age;
private
String sex;
public
static
void
main
(String[] args)
{
AllArgsConstructorExample aace1 =
new
AllArgsConstructorExample(
"zhangsan"
,
"18"
,
"female"
);
System.out.println(aace1.getAge());
AllArgsConstructorExample aace2 = AllArgsConstructorExample.newInstance(
"lisi"
,
"16"
,
"male"
);
System.out.println(aace2.getAge());
}
}
注意:三个注解生成的构造器都可以指定访问权限,同时也可以提供一个静态方法来供调用。三个注解的区别在于对final和@NonNull字段的处理不同
另外关于staticName属性,Lombok源码注释如下:
If
set
, the
generated
constructor
will be
private
,
and
an additional
static
'constructor'
is
generated
with
the same argument
list
that wraps the
real
constructor
.
很明显三个注解都是可以使用构造器直接创建对象的,也可以使用静态方法创建对象,不知道这段注释是什么意思???
@Data注解
等同于@ToString, @EqualsAndHashcode, @Getter, @Setter和@RequiredArgsConstructor一起使用
@Value
@Value注解为不可变类型的@Data,是@Data的一个变种。它标注的类和字段都会被声明为final
@Builder注解
@Builder注解为类生成builder api以供调用。Builder是一种解决包含数量巨大且繁杂的字段的类的一种构建方式。
假如一个类有几十个字段,那么该如何设计这个类呢?
方法一:将几十个字段都添加在构造函数中。简单粗暴,而且在构造函数中为字段初始化也能够保证对象能够正确创建。缺点就是几十个参数只会导致你在创建对象时记错参数的位置,导致不必要的麻烦。
方法二:依赖注入。Spring的核心功能之一就是依赖注入,借助这种思想,我们通过无参构造创建一个对象,然后通过setter方法设置必需的属性。这种方式可以根据需求初始化相关属性,且逻辑清晰,但也会造成代码繁琐,需要调用多次setter方法。
方法三:Builder模式。建造者模式的思想就是将一个大的类的构建分为几部分创建,从而简化创建的复杂性。