Lombok目录
- 什么是Lombok
- 运行原理
- 优势与缺点
- 注解示例
- 稳定版
- val
- var
- @NonNull
- @Cleanup
- @Getter/@Setter
- @ToString
- @EqualsAndHashCode
- @NoArgsConstructor @RequiredArgsConstructor and @AllArgsConstructor
- staticName
- access
- onConstructor
- @Data
- @Value
- staticConstructor
- @Builder
- @Singular
- @Builder.Default
- @SneakyThrows
- @Synchronized
- @With
- @Getter(lazy=true)
- @Log
- 实验版
- @Accessors
- flent
- chain
- prefix
- @ExtensionMethod
- value
- suppressBaseMethods
- @FieldDefaults
- @Delegate
- onMethod= / onConstructor= / onParam=
- @UtilityClass
- @Helper
- @FieldNameConstants
- @SuperBuilder
- @Tolerate
- @Jacksonized
- @StandardException
- 实验版 (删除或增强注解) 慎用 暂不介绍
- @Value: promoted
- @Builder: promoted
- @Wither: renamed to @With, and promoted
- var
什么是Lombok
Project Lombok是一个java库,可以自动插入到编辑器和构建工具中,为java增添情趣。不要再编写另一个getter或equals方法,只需一个注释,您的类就有一个功能齐全的构建器、自动化您的日志记录变量等等。(避免重复造轮子)
运行原理
现有版本采用JSR 269规范(可插拔批注处里API)可以让我们修改编译过程,在编译期融入我们自己的东西,相比通过反射来获取注解,运行时代码效率降低等问题。所以在javac 解析成抽象语法树之后(AST),Lombok根据自己的注解处理器,动态修改AST,增加新的节点,最终通过生成字节码得以体现
优势与缺点
优点:通过注解的形式生成构造器,getter/setter, equals, hascode, toString等方法,提高开发效率让代码变得简洁。
缺点:
- 不支持多种参数构造器的重载
- 降低源码可读性和完整性
- 需要在开发工具中安装对应的插件
- 代码可调试性底
- 影响对项目JDK的升级
注解示例
根据 官网分为稳定版和实验版进行说明
通过maven导入Lombok (截至2022/12/1 最新)
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
稳定版
val
// 使用 Lombok
val example = new ArrayList<String>();
val foo = example.get(0);
// 生成class文件
final ArrayList<String> example = new ArrayList<String>();
final String foo = example.get(0);
var
// 使用Lombok
var example = new ArrayList<String>();
var foo = example.get(0);
// 生成class文件
ArrayList<String> example = new ArrayList<String>();
String foo = example.get(0);
var 和 val 支持配置项
lombok.val.flagUsage = [warning | error] (默认: 未设置)
如果配置,Lombok会将val的任何使用标记为warning或error。
lombok.var.flagUsage = [warning | error] (默认: 未设置)
如果配置,Lombok会将var的任何使用标记为warning或error。
在不明确的情况下 初始化为null时会判断成java.lang.Object
对于复合类型,谨慎使用,避免与我们想象中的类型不一致 导致程序异常
@NonNull
// 使用Lombok
@NonNull Person person
// 生成class文件
if (person == null) {
throw new NullPointerException("person is marked non-null but is null");
}
@Cleanup
// 使用Lombok
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
// 生成class文件
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}
@Getter/@Setter
// 使用Lombok
@Getter @Setter private int age;
@Setter(AccessLevel.PROTECTED) private String name;
// 生成class文件
/**
* Age of the person. Water is wet.
*
* @return The current value of this person's age. Circles are round.
*/
public int getAge() {
return age;
}
/**
* Age of the person. Water is wet.
*
* @param age New value for this person's age. Sky is blue.
*/
public void setAge(int age) {
this.age = age;
}
/**
* Changes the name of this person.
*
* @param name The new value.
*/
protected void setName(String name) {
this.name = name;
}
@ToString
// 使用Lombok
import lombok.ToString;
@ToString( includeFieldNames=false) // 给ToStringExample 生成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; // 给ToStringExample 生成toString方法中去除id属性
public String getName() {
return this.name;
}
@ToString(callSuper=true, includeFieldNames=true) // 实现toString方法输出父类中继承的属性 和 形式为fieldName = fieldValue
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
// 生成class文件
import java.util.Arrays;
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override public String toString() {
return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
}
}
@Override public String toString() {
return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";
}
}
支持的配置项
lombok.toString.includeFieldNames = [true | false] (default: true)
lombok为每个字段生成一个toString响应的片段,形式为fieldName = fieldValue。如果这个设置为false,lombok将省略字段的名称,并简单地部署所有字段值的逗号分隔的列表。
lombok.toString.doNotUseGetters = [true | false] (default: false)
如果设置为true,lombok在生成toString方法时将直接访问字段而不是使用getters(如果有的话)。
lombok.toString.callSuper = [call | skip | warn] (default: skip)
如果设置为call,则如果您的类扩展了某些内容,lombok将生成对toString的父类实现的调用。如果设置为skip,则不会生成此父类调用。如果设置为warn,则也不会生成此父类调用,但lombok会生成警告来告诉您。
lombok.toString.onlyExplicitlyIncluded = [true | false] (default: false)
如果设置为false(默认),那么所有字段(除非static、name以$开头,或者由于明显的原因被排除在外)都将作为toString中包含的默认内容集.。
@ToString.Exclude 将该属性排除在外
@ToString.Include 将该属性包含在内
lombok.toString.flagUsage = [warning | error] (default: not set)
Lombok将@ToString的任何使用标记为警告或错误(如果已配置)。
@EqualsAndHashCode
//使用Lombok
import lombok.EqualsAndHashCode;
@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;
}
}
}
// 生成class文件
import java.util.Arrays;
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof EqualsAndHashCodeExample)) return false;
EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
if (Double.compare(this.score, other.score) != 0) return false;
if (!Arrays.deepEquals(this.tags, other.tags)) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
final long temp1 = Double.doubleToLongBits(this.score);
result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.tags);
return result;
}
protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeExample;
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Square)) return false;
Square other = (Square) o;
if (!other.canEqual((Object)this)) return false;
if (!super.equals(o)) return false;
if (this.width != other.width) return false;
if (this.height != other.height) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + super.hashCode();
result = (result*PRIME) + this.width;
result = (result*PRIME) + this.height;
return result;
}
protected boolean canEqual(Object other) {
return other instanceof Square;
}
}
}
@NoArgsConstructor @RequiredArgsConstructor and @AllArgsConstructor
// 使用Lombok
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;
@RequiredArgsConstructor(staticName = "of") // 生成该类下被final修饰或者non-null字段生成一个构造方法。
@AllArgsConstructor(access = AccessLevel.PROTECTED) // 构造方法的访问修饰符为PROTECTED 生成该类下全部属性的构造方法。
public class ConstructorExample<T> {
private int x, y;
@NonNull private T description;
@NoArgsConstructor //生成无参的构造方法。
public static class NoArgsExample {
@NonNull private String field;
}
}
// 生成class文件
public class ConstructorExample<T> {
private int x, y;
@NonNull private T description;
private ConstructorExample(T description) {
if (description == null) throw new NullPointerException("description");
this.description = description;
}
public static <T> ConstructorExample<T> of(T description) {
return new ConstructorExample<T>(description);
}
@java.beans.ConstructorProperties({"x", "y", "description"})
protected ConstructorExample(int x, int y, T description) {
if (description == null) throw new NullPointerException("description");
this.x = x;
this.y = y;
this.description = description;
}
public static class NoArgsExample {
@NonNull private String field;
public NoArgsExample() {
}
}
}
重要场景:当一个bean类,注入其他bean的时候我们通常用@Autowired ,可以用@AllArgsConstructor或者@RequiredArgsConstructor来代替(实用)
当bean属性注入需要找类型为String名字是name的bean对象 需要使用@RequiredArgsConstructor 当使用@RequiredArgsConstructor 必须加上 final 或者 @NonNull修饰
特殊说明: 通常注解会有几个属性
staticName
生成的构造方法是私有的并且生成一个参数为final变量和@NonNull注解变量,返回类型为当前对象的静态方法 方法名为staticName 值
access
设置构造方法的访问修饰符,PUBLIC、MODULE、PROTECTED、PACKAGE、PRIVATE、NONE ,MODULE 是 Java 9 的新特性,NONE 表示不生成构造方法也不生成静态方法,即停用注解功能
onConstructor
列出的所有注解都放在生成的构造方法上
JDK 7 之前的写法是 onConstructor = @__({@Deprecated}),而 JDK 8 之后的写法是 onConstructor_ = {@Deprecated}
@Data
注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法 合理使用,不要因为只用setter getter方法直接用 按需使用
// 使用 Lombok
import lombok.AccessLevel;
import lombok.Setter;
import lombok.Data;
import lombok.ToString;
@Data public class DataExample {
private final String name;
@Setter(AccessLevel.PACKAGE) private int age; // Set方法 访问修饰方法为 provided
private double score;
private String[] tags;
@ToString(includeFieldNames=true) // toString方法 以FieldName=FieldValue对应
@Data(staticConstructor="of") // 构造方法为私有 并生成静态方法返回当前对象 方法名为staticConstructor值
public static class Exercise<T> {
private final String name;
private final T value;
}
}
// 生成class文件
import java.util.Arrays;
public class DataExample {
private final String name;
private int age;
private double score;
private String[] tags;
public DataExample(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
public void setScore(double score) {
this.score = score;
}
public double getScore() {
return this.score;
}
public String[] getTags() {
return this.tags;
}
public void setTags(String[] tags) {
this.tags = tags;
}
@Override public String toString() {
return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")";
}
protected boolean canEqual(Object other) {
return other instanceof DataExample;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof DataExample)) return false;
DataExample other = (DataExample) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
if (this.getAge() != other.getAge()) return false;
if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
final long temp1 = Double.doubleToLongBits(this.getScore());
result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
result = (result*PRIME) + this.getAge();
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
return result;
}
public static 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> Exercise<T> of(String name, T value) {
return new Exercise<T>(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
@Override public String toString() {
return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
}
protected boolean canEqual(Object other) {
return other instanceof Exercise;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Exercise)) return false;
Exercise<?> other = (Exercise<?>) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
return result;
}
}
}
@Value
作用于类 使所有的成员变量都是final 是 @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter
在注解源码中只有一个属性
staticConstructor
使生成的构造方法私有化 并生成一个返回类型为当前对象的无参静态方法,方法名为staticConstructor值
// 使用Lombok
import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Value;
import lombok.experimental.With;
import lombok.ToString;
@Value public class ValueExample {
String name;
@With(AccessLevel.PACKAGE) @NonFinal int age; // With:生成方法名为with+属性名 返回全参构造方法的对象 修改当前属性的值 NonFinal:保持非final的字段
double score;
protected String[] tags;
@ToString(includeFieldNames=true) // 生成ToString方法 以fieldname = fieldValue对应
@Value(staticConstructor="of") // staticConstructor:构造方法为私有生成静态方法返回对象 方法名为staticConstructor值
public static class Exercise<T> {
String name;
T value;
}
}
// 生成class类
import java.util.Arrays;
public final class ValueExample {
private final String name;
private int age;
private final double score;
protected final String[] tags;
@java.beans.ConstructorProperties({"name", "age", "score", "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;
}
@java.lang.Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ValueExample)) return false;
final ValueExample other = (ValueExample)o;
final Object this$name = this.getName();
final Object other$name = other.getName();
if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
if (this.getAge() != other.getAge()) return false;
if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
return true;
}
@java.lang.Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $name = this.getName();
result = result * PRIME + ($name == null ? 43 : $name.hashCode());
result = result * PRIME + this.getAge();
final long $score = Double.doubleToLongBits(this.getScore());
result = result * PRIME + (int)($score >>> 32 ^ $score);
result = result * PRIME + Arrays.deepHashCode(this.getTags());
return result;
}
@java.lang.Override
public String toString() {
return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";
}
ValueExample withAge(int age) {
return this.age == age ? this : new ValueExample(name, age, score, 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> Exercise<T> of(String name, T value) {
return new Exercise<T>(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
@java.lang.Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ValueExample.Exercise)) return false;
final Exercise<?> other = (Exercise<?>)o;
final Object this$name = this.getName();
final Object other$name = other.getName();
if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
final Object this$value = this.getValue();
final Object other$value = other.getValue();
if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $name = this.getName();
result = result * PRIME + ($name == null ? 43 : $name.hashCode());
final Object $value = this.getValue();
result = result * PRIME + ($value == null ? 43 : $value.hashCode());
return result;
}
@java.lang.Override
public String toString() {
return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
}
}
}
@Builder
对初学者有些难度 理解上费劲些 熟能生巧
使用建造者模式: 用来生成对象 通过对象链式赋值
内部生成步骤:
- 创建一个名为ThisClassBuilder的内部静态类 并具有和实体类相同的属性
- 目标类中的所有属性和未初始化的final字段 都会在构建其中创建对应属性
- 创建一个无参的default构造函数
- 对于实体类中的每个参数,都会对应创建类似于setter的方法 只不过方法名与该参数名像同。并且返回值是构建器本身(便于链式调用)
- 一个build() 方法 调用此方法 根据设置的值进行创建实体对象
- 生成一个toString()方法
- 创建一个builder() 方法 用来创建构建器
@Singular
作用于属性 想要这样来操作集合 需要使用
支持类型:java.util.Iterable,Collection, List
Set,SortedSet,NavigableSet
Map,SortedMap,NavigableMap
Guava’s com.google.common.collect:ImmutableCollection,ImmutableList,ImmutableSet,ImmutableSortedSet
ImmutableMap,ImmutableBiMap,ImmutableSortedMap,ImmutableTable
@Builder.Default
作用于属性,不需要初始化
// 使用Lombok
@Builder
public class User {
private final Integer id;
private final String zipCode = "123456";
private String username;
private String password;
@Singular
private List<String> hobbies;
}
// 生成class
public class User {
private final Integer id;
private final String zipCode = "123456";
private String username;
private String password;
private List<String> hobbies;
User(Integer id, String username, String password, List<String> hobbies) {
this.id = id; this.username = username;
this.password = password; this.hobbies = hobbies;
}
public static User.UserBuilder builder() {return new User.UserBuilder();}
public static class UserBuilder {
private Integer id;
private String username;
private String password;
private ArrayList<String> hobbies;
UserBuilder() {}
public User.UserBuilder id(Integer id) { this.id = id; return this; }
public User.UserBuilder username(String username) { this.username = username; return this; }
public User.UserBuilder password(String password) { this.password = password; return this; }
public User.UserBuilder hobby(String hobby) {
if (this.hobbies == null) {
this.hobbies = new ArrayList();
}
this.hobbies.add(hobby);
return this;
}
public User.UserBuilder hobbies(Collection<? extends String> hobbies) {
if (this.hobbies == null) {
this.hobbies = new ArrayList();
}
this.hobbies.addAll(hobbies);
return this;
}
public User.UserBuilder clearHobbies() {
if (this.hobbies != null) {
this.hobbies.clear();
}
return this;
}
public User build() {
List hobbies;
switch(this.hobbies == null ? 0 : this.hobbies.size()) {
case 0:
hobbies = Collections.emptyList();
break;
case 1:
hobbies = Collections.singletonList(this.hobbies.get(0));
break;
default:
hobbies = Collections.unmodifiableList(new ArrayList(this.hobbies));
}
return new User(this.id, this.username, this.password, hobbies);
}
public String toString() {
return "User.UserBuilder(id=" + this.id + ", username=" + this.username + ", password=" + this.password + ", hobbies=" + this.hobbies + ")";
}
}
}
@SneakyThrows
作用于方法 将当前方法抛出的异常,包装成RuntimeException,骗过编译器 使得调用点可以不用显示处理异常信息
// 使用Lombok
import lombok.SneakyThrows;
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();
}
}
// 生成class
import lombok.Lombok;
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);
}
}
}
@Synchronized
作用于方法 锁住方法代码块 实现同步
// 使用Lombok
import lombok.Synchronized;
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");
}
}
// 生成class
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");
}
}
}
@With
作用于类,生成多个with+变量名的方法(个数为所有成员变量 不包含@NonNull)
作用于变量 生成with+变量名的方法 返回当前对象 需要提供全参(不包含 静态变量)构造方法
// 使用Lombok
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.With;
public class WithExample {
@With(AccessLevel.PROTECTED) @NonNull private final String name;
@With private final int age;
public WithExample(@NonNull String name, int age) {
this.name = name;
this.age = age;
}
}
// 生成class
import lombok.NonNull;
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);
}
}
@Getter(lazy=true)
Lombok 生成一个getter,第一次调用这个getter时计算一个值并从那时起缓存它。自动去管理线程安全的问题,不会存在重复赋值的问题,使用此功能,需要创建一个private final变量,并且使用运行成本高的表达式对其进行初始化
// 使用 Lombok
import lombok.Getter;
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;
}
}
// 生成class
public class GetterLazyExample {
private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<java.lang.Object>();
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;
}
}
@Log
生成一个logger字段
// 使用Lombok
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
@Log
public class LogExample {
public static void main(String... args) {
log.severe("Something's wrong here");
}
}
@Slf4j
public class LogExampleOther {
public static void main(String... args) {
log.error("Something else is wrong here");
}
}
@CommonsLog(topic="CounterLog")
public class LogExampleCategory {
public static void main(String... args) {
log.error("Calling the 'CounterLog' with a message");
}
}
// 生成class
public class LogExample {
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
public static void main(String... args) {
log.severe("Something's wrong here");
}
}
public class LogExampleOther {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
public static void main(String... args) {
log.error("Something else is wrong here");
}
}
public class LogExampleCategory {
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");
public static void main(String... args) {
log.error("Calling the 'CounterLog' with a message");
}
}
实验版
@Accessors
可用于类及属性字段 用于生成getter和setter方法时的一些设置
属性
flent
为true: 生成的getter方法忽略get,并且setter方法返回对象本身,getter方法返回属性类型。
为false: @Data默认的属性.即(默认为false 生成的为getUserName(),为true时为userName() )
chain
为true: getter和setter方法和默认时一样,并且遵循驼峰命名,且setter方法返回的是对象本身,和Fient=true时返回类型一样
为false: @Data默认形式
prefix
属性值为String类型数组,意思就是比如prefix='user’且一个属性字段为String userName,则生成就为get方法:String getName();set方法:setName(String userName).
// 使用Lombok
import lombok.experimental.Accessors;
import lombok.Getter;
import lombok.Setter;
@Accessors(fluent = true)
public class AccessorsExample {
@Getter @Setter
private int age = 10;
}
class PrefixExample {
@Accessors(prefix = "f") @Getter
private String fName = "Hello, World!";
}
// 生成class
public class AccessorsExample {
private int age = 10;
public int age() {
return this.age;
}
public AccessorsExample age(final int age) {
this.age = age;
return this;
}
}
class PrefixExample {
private String fName = "Hello, World!";
public String getName() {
return this.fName;
}
}
@ExtensionMethod
作用于类 向类中添加方法 无需创建新的子类, 变量与方法参数,返回值类型必须一样
属性介绍
value
指定添加类
suppressBaseMethods
如果为 false,基础类型不能调用方法,默认为 true
如果 suppressBaseMethods = false
1、变量与方法参数、返回值的类型不能为基础类型
2、自定义方法不可与引用对象的方法重名(无法使用 变量.方法名)
// 使用Lombok
@ExtensionMethod(value = LongYiYi.class, suppressBaseMethods = true)
public class QiaoXin {
public static void main(String[] args) {
int num = 0;
num = num.aaa();
System.out.println(num); // 输出结果为 1;
"乔欣".print();
List<String> list = new ArrayList<String>();
list.add();
}
}
class LongYiYi {
public static int aaa(int num) {
return ++num;
}
public static void print(String name) {
System.out.println(name);
}
public static void add(List<String> list) {
list.add("龙一一");
}
}
// 生成class文件
public class QiaoXin {
public static void main(String[] args) {
int num = 0;
num = LongYiYi.aaa(num);
System.out.println(num);
LongYiYi.print("乔欣");
List list = new ArrayList();
LongYiYi.add(list);
}
}
@FieldDefaults
作用于类或枚举中的每个字段添加访问修饰符,为注释的类或枚举中的每个字段添加final
如果保持非final字段 可以用 @NonFinal
作用于实例字段中不添加final 需要使用@FieldDefaults(makeFinal=true)
@FieldDefaults(level=AccessLevel.PRIVATE)
任何还没有访问修饰符的字段(即任何看起来像包私有访问的字段)都被改变为具有适当的访问修饰符
任何必须保持包私有的字段都可以用@PackagePrivate
// 使用Lombok
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import lombok.experimental.PackagePrivate;
@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE)
public class FieldDefaultsExample {
public final int a;
int b;
@NonFinal int c;
@PackagePrivate int d;
FieldDefaultsExample() {
a = 0;
b = 0;
d = 0;
}
}
// 生成class
public class FieldDefaultsExample {
public final int a;
private final int b;
private int c;
final int d;
FieldDefaultsExample() {
a = 0;
b = 0;
d = 0;
}
}
@Delegate
任何字段或无参数方法都可以用@Delegate来注解,让lombok生成转发对这个字段的调用(或调用这个方法的结果)的委托方法。
// 使用Lombok
import java.util.ArrayList;
import java.util.Collection;
import lombok.experimental.Delegate;
public class DelegationExample {
private interface SimpleCollection {
boolean add(String item);
boolean remove(Object item);
}
@Delegate(types=SimpleCollection.class)
private final Collection<String> collection = new ArrayList<String>();
}
class ExcludesDelegateExample {
long counter = 0L;
private interface Add {
boolean add(String x);
boolean addAll(Collection<? extends String> x);
}
@Delegate(excludes=Add.class)
private final Collection<String> collection = new ArrayList<String>();
public boolean add(String item) {
counter++;
return collection.add(item);
}
public boolean addAll(Collection<? extends String> col) {
counter += col.size();
return collection.addAll(col);
}
}
// 生成class
import java.util.ArrayList;
import java.util.Collection;
public class DelegationExample {
private interface SimpleCollection {
boolean add(String item);
boolean remove(Object item);
}
private final Collection<String> collection = new ArrayList<String>();
@java.lang.SuppressWarnings("all")
public boolean add(final java.lang.String item) {
return this.collection.add(item);
}
@java.lang.SuppressWarnings("all")
public boolean remove(final java.lang.Object item) {
return this.collection.remove(item);
}
}
class ExcludesDelegateExample {
long counter = 0L;
private interface Add {
boolean add(String x);
boolean addAll(Collection<? extends String> x);
}
private final Collection<String> collection = new ArrayList<String>();
public boolean add(String item) {
counter++;
return collection.add(item);
}
public boolean addAll(Collection<? extends String> col) {
counter += col.size();
return collection.addAll(col);
}
@java.lang.SuppressWarnings("all")
public int size() {
return this.collection.size();
}
@java.lang.SuppressWarnings("all")
public boolean isEmpty() {
return this.collection.isEmpty();
}
@java.lang.SuppressWarnings("all")
public boolean contains(final java.lang.Object arg0) {
return this.collection.contains(arg0);
}
@java.lang.SuppressWarnings("all")
public java.util.Iterator<java.lang.String> iterator() {
return this.collection.iterator();
}
@java.lang.SuppressWarnings("all")
public java.lang.Object[] toArray() {
return this.collection.toArray();
}
@java.lang.SuppressWarnings("all")
public <T extends .java.lang.Object>T[] toArray(final T[] arg0) {
return this.collection.<T>toArray(arg0);
}
@java.lang.SuppressWarnings("all")
public boolean remove(final java.lang.Object arg0) {
return this.collection.remove(arg0);
}
@java.lang.SuppressWarnings("all")
public boolean containsAll(final java.util.Collection<?> arg0) {
return this.collection.containsAll(arg0);
}
@java.lang.SuppressWarnings("all")
public boolean removeAll(final java.util.Collection<?> arg0) {
return this.collection.removeAll(arg0);
}
@java.lang.SuppressWarnings("all")
public boolean retainAll(final java.util.Collection<?> arg0) {
return this.collection.retainAll(arg0);
}
@java.lang.SuppressWarnings("all")
public void clear() {
this.collection.clear();
}
}
onMethod= / onConstructor= / onParam=
暂不介绍
@UtilityClass
作用于类 将类标记为final 并且类,内部类中的方法 字段 都标记为static
// 使用Lombok
import lombok.experimental.UtilityClass;
@UtilityClass
public class UtilityClassExample {
private final int CONSTANT = 5;
public int addSomething(int in) {
return in + CONSTANT;
}
}
// 生成class
public final class UtilityClassExample {
private static final int CONSTANT = 5;
private UtilityClassExample() {
throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
public static int addSomething(int in) {
return in + CONSTANT;
}
}
@Helper
作用于方法内部类,使内部类中的方法暴露在外面可以被直接调用
// 使用Lombok
import lombok.experimental.Helper;
public class HelperExample {
int someMethod(int arg1) {
int localVar = 5;
@Helper class Helpers {
int helperMethod(int arg) {
return arg + localVar;
}
}
return helperMethod(10);
}
}
// 生成class
public class HelperExample {
int someMethod(int arg1) {
int localVar = 5;
class Helpers {
int helperMethod(int arg) {
return arg + localVar;
}
}
Helpers $Helpers = new Helpers();
return $Helpers.helperMethod(10);
}
}
@FieldNameConstants
生成了一个内部类 Fields
// 使用Lombok
import lombok.experimental.FieldNameConstants;
import lombok.AccessLevel;
@FieldNameConstants
public class FieldNameConstantsExample {
private final String iAmAField;
private final int andSoAmI;
@FieldNameConstants.Exclude private final int asAmI;
}
// 生成class
public class FieldNameConstantsExample {
private final String iAmAField;
private final int andSoAmI;
private final int asAmI;
public static final class Fields {
public static final String iAmAField = "iAmAField";
public static final String andSoAmI = "andSoAmI";
}
}
@SuperBuilder
(慎用)
@Builder 的升级版,不支持对基类成员属性的构造
属性
builderMethodName:创建内部静态类的方法名,默认值为 builder
buildMethodName:创建实体类的方法名,默认值为 build
toBuilder:设置为 true 可以对这个对象进行拷贝生成新的对象,可以再修改,默认为 false
setterPrefix:setter 方法的前缀
注意事项
- 基类和派生类不能同时存在 @Builder
- 如果基类使用了 @SuperBuilder,那么派生类必须存在 @SuperBuilder 或者写出参数为:基类Builder<?, ?> 的构造方法
- @SuperBuilder 并不像 @Builder 功能那么多,比如非 final 字段设置默认值,@SuperBuilder 并不支持
// 使用Lombok
@SuperBuilder
public class ParentClass {
private final String a;
private final String b;
}
@SuperBuilder
public class ChildClass extends ParentClass{
private final String c;
}
// 生成class
ChildClass.builder().a("testA").b("testB").c("testC").build();
@Tolerate
任何方法或构造函数都可以用注释,@Tolerate并且lombok会像它不存在一样起作用。
缺点
难以支持递归委派
// 使用Lombok
import lombok.experimental.Tolerate;
public class TolerateExample {
@Setter
private Date date;
@Tolerate
public void setDate(String date) {
this.date = Date.valueOf(date);
}
}
// 生成class
public class TolerateExample {
@Setter
private Date date;
public void setDateFromString(String date) {
this.date = Date.valueOf(date);
}
}
@Jacksonized
该@Jacksonized注释是一个附加注释的@Builder和@SuperBuilder。它会自动配置生成的生成器类,以供Jackson的反序列化使用。它只有在还存在a@Builder或a的上下文中出现时才起作用@SuperBuilder。否则会发出警告。
@StandardException
放置任何扩展了某些{@code java.lang.Throwable}类型的类,以添加4个常见异常构造函数
// 使用Lombok
import lombok.experimental.StandardException;
@StandardException
public class ExampleException extends Exception {
}
// 生成class
public class ExampleException extends Exception {
public ExampleException() {
this(null, null);
}
public ExampleException(String message) {
this(message, null);
}
public ExampleException(Throwable cause) {
this(cause != null ? cause.getMessage() : null, cause);
}
public ExampleException(String message, Throwable cause) {
super(message);
if (cause != null) super.initCause(cause);
}
}