@Getter、@Setter
可以使用 @Getter 或 @Setter 注释任何类或字段,Lombok 会自动生成默认的 getter/setter 方法。如果该字段被称为 foo,则 getter 的方法名为 getFoo;如果该字段的类型为 boolean,则为 isFoo。当在类上使用该注释时,该注释会注释该类中的所有非静态字段。
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {
// 生成的getter方法的访问级别
lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;
// 废弃
AnyAnnotation[] onMethod() default {};
// 是否启用延迟初始化
boolean lazy() default false;
}
默认生成的 getter/setter 方法是公共的,除非你明确指定一个 AccessLevel。
public enum AccessLevel {
PUBLIC, MODULE, PROTECTED, PACKAGE, PRIVATE,
/** Represents not generating anything or the complete lack of a method. */
NONE;
}
可以使用特殊的 AccessLevel.NONE 访问级别来手动禁用任何字段的 getter/setter 自动生成。这使得我们可以覆盖类上的 @Getter,@Setter 或 @Data 注释的行为。
@Getter 注解还支持一个 lazy 属性,该属性默认为 false。当设置为 true 时,会启用延迟初始化,即当首次调用相应 getter 方法时才进行初始化,内部通过同步代码块进行首次初始化。
构造函数
1. @NoArgsConstructor
使用 @NoArgsConstructor 注解可以为指定类生成默认构造函数,@NoArgsConstructor 注解定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {
/**
* 如果设置了该属性,生成的构造函数将会是私有的,并且生成一个staticName指定的静态构造方法(内部调用构造函数)
*/
String staticName() default "";
/**
* 设置生成的构造函数的访问级别,默认是public
*/
AccessLevel access() default lombok.AccessLevel.PUBLIC;
/**
* 若设置为true,则初始化所有final的字段为0/null/false
* 如果为false,当有final字段存在时编译器会报错
*/
boolean force() default false;
}
代码示例:
@NoArgsConstructor(staticName = "getInstance")
public class NoArgsConstructorDemo {
private long id;
private String name;
private int age;
}
以上代码经过 Lombok 编译后,会生成如下代码:
public class NoArgsConstructorDemo {
private long id;
private String name;
private int age;
private NoArgsConstructorDemo() {
}
public static NoArgsConstructorDemo getInstance() {
return new NoArgsConstructorDemo();
}
}
2. @AllArgsConstructor
使用 @AllArgsConstructor 注解可以为指定类生成包含所有成员的构造函数。
3. @RequiredArgsConstructor
使用 @RequiredArgsConstructor 注解可以为指定类初始化必需的成员变量,如 final 成员变量,针对必需初始化的成员变量生成对应的构造函数。
@EqualsAndHashCode
使用 @EqualsAndHashCode 注解可以为指定类生成 equals 和 hashCode 方法,默认使用的是所有非 static、非 transient 修饰的字段,且不考虑父类属性。@EqualsAndHashCode 注解的定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
/**
* 如果为true,则子类生成的equals和hashCode方法会调用父类的相应方法
*/
boolean callSuper() default false;
/**
* 如果字段的getter方法可用,在生成的equals和hashCode方法中会调用它们,否则直接访问字段。
* 如果设置为true,则始终会使用直接字段访问而不会调用字段的getter方法。
*/
boolean doNotUseGetters() default false;
/**
* 如果为true,则生成的equals和hashCode方法仅包含显式标记为@EqualsAndHashCode.Include的字段和方法。
* 如果为false,则默认包含所有非static、非transient字段。
*/
boolean onlyExplicitlyIncluded() default false;
/**
* 如果想要在生成的equals和hashCode方法中排除某字段,则通过该注解修饰对应字段
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {}
/**
* 如果想要在生成的equals和hashCode方法中使用某字段,则通过该注解修饰对应字段
* 需要将onlyExplicitlyIncluded设为true,来精确控制使用的字段
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
String replaces() default "";
}
}
@EqualsAndHashCode.Exclude 代码示例:
public class EqualsAndHashCodeExample {
public static void main(String[] args) {
Person person1 = new Person("a", "1");
Person person2 = new Person("b", "1");
System.out.println(person1.equals(person2));
}
@EqualsAndHashCode
@AllArgsConstructor
private static class Person {
@EqualsAndHashCode.Exclude
private final String name;
private final String identity;
}
}
// 输出为:true
@EqualsAndHashCode.Include 代码示例:
public class EqualsAndHashCodeExample {
public static void main(String[] args) {
Person person1 = new Person("a", "1");
Person person2 = new Person("b", "1");
System.out.println(person1.equals(person2));
}
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor
private static class Person {
private final String name;
@EqualsAndHashCode.Include
private final String identity;
}
}
// 输出为:true
callSuper 使用示例:
public class EqualsAndHashCodeExample {
public static void main(String[] args) {
Employee employee1 = new Employee("a", "1", "A");
Employee employee2 = new Employee("b", "1", "A");
System.out.println(employee1.equals(employee2));
}
@EqualsAndHashCode
@AllArgsConstructor
private static class Person {
private final String name;
private final String identity;
}
@EqualsAndHashCode(callSuper = true)
private static class Employee extends Person {
private String company;
public Employee(String name, String identity, String company) {
super(name, identity);
this.company = company;
}
}
}
// 输出为:false,因为考虑了父类的name属性
@ToString
使用 @ToString 注解可以为指定类生成 toString 方法,@ToString 注解的定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ToString {
/**
* 打印输出时是否包含字段的名称
*/
boolean includeFieldNames() default true;
/**
* 打印输出的结果中是否包含父类的toString方法的返回结果
*/
boolean callSuper() default false;
/**
* 如果字段的getter方法可用,在生成的toString方法中会调用它们,否则直接访问字段。
* 如果设置为true,则始终会使用直接字段访问而不会调用字段的getter方法。
*/
boolean doNotUseGetters() default false;
/**
* 如果为true,则生成的toString方法仅包含显式标记为@ToString.Include的字段和方法。
* 如果为false,则默认包含所有非static字段。
*/
boolean onlyExplicitlyIncluded() default false;
/**
* 如果想要在生成的toString方法中排除某字段,则通过该注解修饰对应字段
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {}
/**
* 如果想要在生成的toString方法中使用某字段,则通过该注解修饰对应字段
* 需要将onlyExplicitlyIncluded设为true,来精确控制使用的字段
* 如果修饰在一个方法上,则在输出中包含该方法的返回值。
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
// 打印顺序的优先级,首先打印更高的等级,相同等级的成员按它们在源文件中出现的顺序打印
int rank() default 0;
String name() default "";
}
}
使用示例如下:
public class ToStringDemo {
public static void main(String[] args) {
Employee employee = new Employee("a", "1", "A");
System.out.println(employee.toString());
}
@ToString(onlyExplicitlyIncluded = true)
@AllArgsConstructor
private static class Person {
@ToString.Include(rank = 1)
private final String name;
@ToString.Include(rank = 2)
private final String identity;
private final String other;
}
@ToString(includeFieldNames = false, callSuper = true)
private static class Employee extends Person {
private final String company;
@ToString.Exclude
private final String exclude;
public Employee(String name, String identity, String company) {
super(name, identity, "other");
this.company = company;
this.exclude = "exclude";
}
}
}
// 输出如下:ToStringDemo.Employee(super=ToStringDemo.Person(identity=1, name=a), A)
@Data
@Data 是一个复合注解,常用于普通的 POJO 类。它的功能与同时使用以下注解的效果是一样的:
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
@Value
@Value 注解和 @Data 注解一样也是个复合注解,但 @Value 注解常用于不可变类,它的功能与同时使用以下注解的效果是一样的:
@Getter
@FieldDefaults
@AllArgsConstructor
@ToString
@EqualsAndHashCode
可以看到 @Value 注解不会生成 setter 方法,并且构造器封装了全部属性。其中,@FieldDefaults 注解的使用方式为:@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE),即它会把所有实例属性的访问级别修改为 private final 修饰。
@Builder
使用 @Builder 注解可以为指定类实现建造者模式,建造者模式就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程。该注解可以放在类、构造函数或方法上。@Builder 注解的定义如下:
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {
/**
* 用@Default注释的字段必须有一个初始化表达式;如果在构建期间未设置该字段,则将该表达式将作为字段默认值使用。
*/
@Target(FIELD)
@Retention(SOURCE)
public @interface Default {}
// 指定实体类中创建Builder的方法名称,默认为builder,一般不需要修改
String builderMethodName() default "builder";
// 指定Builder中用来构建实体类的方法名称,默认为build,一般不需要修改
String buildMethodName() default "build";
// 指定创建的建造者类的名称,默认为:实体类名+Builder后缀
String builderClassName() default "";
/**
* 使用toBuilder可以实现以一个实例为基础继续创建一个对象,也就是可以重用原来对象的值
* 但只是值复用,返回的是一个新的对象
*/
boolean toBuilder() default false;
@Target({FIELD, PARAMETER})
@Retention(SOURCE)
public @interface ObtainVia {
String field() default "";
String method() default "";
boolean isStatic() default false;
}
}
@Builder 注解使用示例如下:
public class BuilderDemo {
@Builder(toBuilder = true)
@ToString
private static class Person {
private final String name;
private final String identity;
@Builder.Default
private final long birthday = System.currentTimeMillis();
}
public static void main(String[] args) {
Person person = Person.builder().name("xl").identity("123").build();
System.out.println(person);
person = person.toBuilder().identity("456").birthday(111).build();
System.out.println(person);
}
}
// 输出如下:
BuilderDemo.Person(name=xl, identity=123, birthday=1635586221889)
BuilderDemo.Person(name=xl, identity=456, birthday=111)
此外,@Builder 注解还可以配合 @Singular 注解使用,用来对集合类型的属性添加单个元素。当用 @Singular 注释一个集合字段(使用 @Builder 注释类)时,Lombok 会为该字段提供三个构建方法:
- 一个用来向集合添加单个元素
- 一个用来将另一个集合的所有元素添加到集合中
- 清空集合元素
@Builder 配合 @Singular 注解使用示例:
public class BuilderDemo2 {
@Builder
@ToString
private static class Person {
@Singular("hobby")
private List<String> hobby;
}
public static void main(String[] args) {
List<String> hobby = new ArrayList<>();
hobby.add("football");
Person person = Person.builder()
.hobby(hobby)
.hobby("basketball")
// .clearHobby()
.build();
System.out.println(person);
}
}
// 输入如下:
BuilderDemo2.Person(hobby=[football, basketball])
日志
1. @Log
@Log 注解采用 JDK 提供的日志实现,为指定类生成一个 log 静态属性:
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
2. @Log4j、@Log4j2
@Log4j、Log4j2 注解采用 Log4j、Log4j2 提供的日志实现,为指定类生成一个 log 静态属性:
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
3. @CommonsLog
@CommonsLog 注解采用 Common Logging 提供的日志实现(日志接口),为指定类生成一个 log 静态属性:
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
4. @Slf4j
@Slf4j 注解采用 Slf4j 提供的日志实现(也是日志接口),为指定类生成一个 log 静态属性:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@Cleanup
@Cleanup 注解用于自动管理资源,用来饰局部变量,在当前变量范围内即将执行完毕退出之前会自动进行资源的清理,为变量自动生成 try-finally 这样的代码来关闭资源。
@SneakyThrows
@SneakyThrows 注解用于自动抛出受检异常,而无需在方法中使用 throw 语句显式抛出。注解定义如下:
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface SneakyThrows {
// 设置你希望向上抛的异常类
Class<? extends Throwable>[] value() default java.lang.Throwable.class;
}
@Synchronized
@Synchronized 是同步方法修饰符的更安全的变体。与 synchronized 一样,该注解只能应用在静态和实例方法上面。它的操作类似于 synchronized 关键字,但是它锁定在不同的对象上。synchronized 关键字应用在实例方法时锁定的是 this 对象,而应用在静态方法上锁定的是类对象。对于 @Synchronized 注解声明的方法来说,它锁定的是内部生成的 $lock(实例方法)或 $Lock(静态方法)对象。@Synchronized 注解的定义如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Synchronized {
/**
* 指定要锁定的对象的名称
*/
String value() default "";
}
@Synchronized 注解使用示例:
public class SynchronizedDemo {
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");
}
}
以上代码经过 Lombok 编译后,会生成如下代码:
public class SynchronizedDemo {
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object();
public SynchronizedDemo() {
}
public static void hello() {
synchronized($LOCK) {
System.out.println("world");
}
}
public int answerToLife() {
synchronized(this.$lock) {
return 42;
}
}
public void foo() {
synchronized(this.readLock) {
System.out.println("bar");
}
}
}