-
Lombok简介
Lombok是一种Java的实用工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现Lombok,开发人员可以节省构建getter/setter以及诸如hashCode()和equals()这样的方法。Lombok会在编译时修改插入代码,因此不会影响任何运行时的性能。
-
安装Lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
Jetbrains IntelliJ IDEA用户需要安装插件
-
Lombok用法
-
@Data注解
@Data直接修饰POJO或者beans, getter所有的变量,setter所有不为final的变量。如果不需要默认的生成方式,直接填写你需要的annotation的就可以了。默认生成的所有的annotation都是public的,如果需要不同权限修饰符可以使用AccessLevel选项。当然@Data 也可以使用staticConstructor选项生成一个静态方法。包含了以下几种注解:
注解 | 生成 | 选项 |
---|---|---|
@Getter / @Setter | getter / setter 方法 | / |
@ToString | toString方法 | includeFieldNames,toString方法是否输出成员变量名,可选值true/false,默认为true |
@EqualsAndHashCode | equals()和hashCode()方法 | / |
@RequiredArgsConstructor | 包含非空参数(未初始化的final成员变量或者@NonNull成员变量)的构造器 | / |
POJO添加了@Data注解,相当于添加了上述五个注解,示例代码:
@Data
public class DataExample {
private final String name;
private final String name1 = "zhuoli";
@NonNull
private String name2;
@NonNull
private String name3 = "zhuoli";
@Setter(AccessLevel.PACKAGE)
private int age;
private double score;
private String[] tags;
@ToString(includeFieldNames=false)
@Data(staticConstructor="of")
public static class Exercise<T> {
private final String name;
private final T value;
}
}
编译后生成的class文件:
public class DataExample {
private final String name;
private final String name1 = "zhuoli";
@NonNull
private String name2;
@NonNull
private String name3 = "zhuoli";
private int age;
private double score;
private String[] tags;
public DataExample(String name, @NonNull String name2) {
if (name2 == null) {
throw new NullPointerException("name2");
} else {
this.name = name;
this.name2 = name2;
}
}
public String getName() {
return this.name;
}
public String getName1() {
this.getClass();
return "zhuoli";
}
@NonNull
public String getName2() {
return this.name2;
}
@NonNull
public String getName3() {
return this.name3;
}
public int getAge() {
return this.age;
}
public double getScore() {
return this.score;
}
public String[] getTags() {
return this.tags;
}
public void setName2(@NonNull String name2) {
if (name2 == null) {
throw new NullPointerException("name2");
} else {
this.name2 = name2;
}
}
public void setName3(@NonNull String name3) {
if (name3 == null) {
throw new NullPointerException("name3");
} else {
this.name3 = name3;
}
}
public void setScore(double score) {
this.score = score;
}
public void setTags(String[] tags) {
this.tags = tags;
}
public boolean equals(Object o) {
//省略
}
protected boolean canEqual(Object other) {
return other instanceof DataExample;
}
public int hashCode() {
}
public String toString() {
return "DataExample(name=" + this.getName() + ", name1=" + this.getName1() + ", name2=" + this.getName2() + ", name3=" + this.getName3() + ", age=" + this.getAge() + ", score=" + this.getScore() + ", tags=" + Arrays.deepToString(this.getTags()) + ")";
}
void setAge(int age) {
this.age = age;
}
public static class Exercise<T> {
private final String name;
private final T value;
public String toString() {
return "DataExample.Exercise(" + this.getName() + ", " + this.getValue() + ")";
}
private Exercise(String name, T value) {
this.name = name;
this.value = value;
}
public static <T> DataExample.Exercise<T> of(String name, T value) {
return new DataExample.Exercise(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
public boolean equals(Object o) {
//省略
}
protected boolean canEqual(Object other) {
return other instanceof DataExample.Exercise;
}
public int hashCode() {
//省略
}
}
}
值得注意的是name1和name3因为已经初始化,生成的构造函数参数中不包含这两项,@Setter使用了AccessLevel.PACKAGE选项,所以生成的setter方法美加权限修饰符,为包访问权限。Exercise内部@ToString注解添加了includeFieldNames=false选项,所以生成的toString方法不包含变量名,@Data添加了staticConstructor=”of”属性,所以生成了静态构造函数of。
-
@Value注解
@Value与@Data的主要区别就是,如果成员变量不加@NonFinal ,编译后生成的类所有的成员变量都会是final的,相应的,就没有set方法了,示例代码:
@Value
public class ValueExample {
private String name;
@Wither(AccessLevel.PACKAGE)
@NonFinal
private int age;
private double score;
protected String[] tags;
@ToString
@Value(staticConstructor="of")
public static class Exercise<T> {
String name;
T value;
}
}
编译后生成的class文件:
public final class ValueExample {
private final String name;
private int age;
private final double score;
protected final String[] tags;
public ValueExample(String name, int age, double score, String[] tags) {
this.name = name;
this.age = age;
this.score = score;
this.tags = tags;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public double getScore() {
return this.score;
}
public String[] getTags() {
return this.tags;
}
public boolean equals(Object o) {
//省略
}
public int hashCode() {
//省略
}
public String toString() {
return "ValueExample(name=" + this.getName() + ", age=" + this.getAge() + ", score=" + this.getScore() + ", tags=" + Arrays.deepToString(this.getTags()) + ")";
}
ValueExample withAge(int age) {
return this.age == age ? this : new ValueExample(this.name, age, this.score, this.tags);
}
public static final class Exercise<T> {
private final String name;
private final T value;
private Exercise(String name, T value) {
this.name = name;
this.value = value;
}
public static <T> ValueExample.Exercise<T> of(String name, T value) {
return new ValueExample.Exercise(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
public boolean equals(Object o) {
//省略
}
public int hashCode() {
//省略
}
public String toString() {
return "ValueExample.Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
}
}
}
可以看到,除了@NonFinal标注的成员变量age,其他成员变量编译后都变成final,但是age成员变量出现在了构造函数中(这一点跟@RequiredArgsConstructor注解有点违背,我也每太看懂)。同时生成了一个包访问权限的WithAge方法,返回一个类实例,不多说,看一下代码就能看懂
-
@Builder注解
@Builder注解标注在类、构造器或方法上,可生成各种builder APIs,允许开发者以如下方式调用:
Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
@Builder
@ToString
@Getter
public class BuilderExample {
/*如果created没有被build赋值,则取默认值*/
@Builder.Default
private long created = System.currentTimeMillis();
private String name;
private int age;
/*表明成员变量是collection*/
@Singular
private Set<String> occupations;
}
调用示例:
@Test
public void builderTest(){
BuilderExample builderExample = BuilderExample.builder().name("zhuoli").age(22).occupation("haha").build();
assertThat(builderExample.getOccupations(), containsInAnyOrder("haha"));
BuilderExample builderExample1 = BuilderExample.builder().occupations(Sets.newHashSet("this", "is", "builder")).build();
assertThat(builderExample1.getOccupations(), containsInAnyOrder("this", "is", "builder"));
}
-
@Log注解
@Log注解标注在类上,并根据不同的注解生成不同类型的日志logger对象,但是实例名称都是log,修饰属性都是private static final,目前支持以下几种logger:
注解 | 生成对象 |
---|---|
@CommonsLog | org.apache.commons.logging.Log |
@JBossLog | org.jboss.logging.Logger |
@Log | java.util.logging.Logger |
@Log4j | org.apache.log4j.Logger |
@Log4j2 | org.apache.log4j.LogManager |
@Slf4j | org.slf4j.Logger |
@XSlf4j | org.slf4j.ext.XLogger |
如@CommonsLog相当于:
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Slf4j相当于:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
更多细节,请参考官方文档
-
@XXXConstructor注解
该系列注解提供自动生成构造函数的功能,主要分为以下三类:
注解 | 生成构造器 |
---|---|
@NoArgsConstructor | 无参构造器 |
@RequiredArgsConstructor | 包含非空参数(未初始化的final成员变量或者@NonNull成员变量)的构造器 |
@AllArgsConstructor | 包含所有非static成员、未初始化的final成员的构造器 |
@AllArgsConstructor
public class AllArgsConstructorExample {
private Integer x;
private Integer y;
private static Integer z;
private final Integer z1;
private final Integer z2 = 2;
private static final Integer z3 = 1;
}
编译后生成的代码:
public class AllArgsConstructorExample {
private Integer x;
private Integer y;
private static Integer z;
private final Integer z1;
private final Integer z2 = 2;
private static final Integer z3 = 1;
public AllArgsConstructorExample(Integer x, Integer y, Integer z1) {
this.x = x;
this.y = y;
this.z1 = z1;
}
}
static成员变量z、z3,已初始化的成员变量z2没有出现在构造函数中
-
@NonNull注解
@NonNull注解提供成员变量的非空检查
public NonNullExample(@NonNull Person person) {
super("Hello");
this.name = person.getName();
}
// 等同于
public NonNullExample(Person person) {
super("Hello");
if (person == null) {
throw new NullPointerException("person");
}
this.name = person.getName();
}
-
@SneakyThrows注解
@SneakyThrows注解的方法会自动抛出受检异常,而无需显式在方法上使用throws语句
-
@Synchronized注解
@Synchronized注解标注在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性$lock或$LOCK。示例代码:
public class SynchronizedExample {
private final Object readLock = new Object();
@Synchronized
public static void hello() {
System.out.println("world");
}
@Synchronized
public int answerToLife() {
return 42;
}
@Synchronized("readLock")
public void foo() {
System.out.println("bar");
}
}
// 等同于
public class SynchronizedExample {
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object();
public static void hello() {
synchronized($LOCK) {
System.out.println("world");
}
}
public int answerToLife() {
synchronized($lock) {
return 42;
}
}
public void foo() {
synchronized(readLock) {
System.out.println("bar");
}
}
}
- @Getter(lazy=true)注解
@Getter(lazy=true)注解可以替代经典的Double Check Lock样板代码,实现单例,示例代码:
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;
}
}
// 等同于
public class GetterLazyExample {
private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<>();
public double[] getCached() {
java.lang.Object value = this.cached.get();
if (value == null) {
synchronized(this.cached) {
value = this.cached.get();
if (value == null) {
final double[] actualValue = expensive();
value = actualValue == null ? this.cached : actualValue;
this.cached.set(value);
}
}
}
return (double[])(value == this.cached ? null : value);
}
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
}
示例代码:码云 – 卓立 – lombok
参考链接: